d0028bd69fcd17cd1943608cb8c4a9eb0ed0b465
[alexxy/gromacs.git] / src / external / tng_io / src / lib / tng_io.c
1 /* This code is part of the tng binary trajectory format.
2  *
3  * Written by Magnus Lundborg
4  * Copyright (c) 2012-2014, The GROMACS development team.
5  * Check out http://www.gromacs.org for more information.
6  *
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the Revised BSD License.
10  */
11
12 #ifdef USE_STD_INTTYPES_H
13 #include <inttypes.h>
14 #endif
15
16 #include <limits.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <time.h>
20 #include <math.h>
21 #ifdef USE_ZLIB
22 #include <zlib.h>
23 #endif
24
25 #include "tng/tng_io.h"
26 #include "tng/md5.h"
27 #include "compression/tng_compress.h"
28 #include "tng/version.h"
29
30
31 struct tng_bond {
32     /** One of the atoms of the bond */
33     int64_t from_atom_id;
34     /** The other atom of the bond */
35     int64_t to_atom_id;
36 };
37
38 struct tng_atom {
39     /** The residue containing this atom */
40     tng_residue_t residue;
41     /** A unique (per molecule) ID number of the atom */
42     int64_t id;
43     /** The atom_type (depending on the forcefield) */
44     char *atom_type;
45     /** The name of the atom */
46     char *name;
47 };
48
49 struct tng_residue {
50     /** The chain containing this residue */
51     tng_chain_t chain;
52     /** A unique (per chain) ID number of the residue */
53     int64_t id;
54     /** The name of the residue */
55     char *name;
56     /** The number of atoms in the residue */
57     int64_t n_atoms;
58     /** A list of atoms in the residue */
59     int64_t atoms_offset;
60 };
61
62 struct tng_chain {
63     /** The molecule containing this chain */
64     tng_molecule_t molecule;
65     /** A unique (per molecule) ID number of the chain */
66     int64_t id;
67     /** The name of the chain */
68     char *name;
69     /** The number of residues in the chain */
70     int64_t n_residues;
71     /** A list of residues in the chain */
72     tng_residue_t residues;
73 };
74
75 struct tng_molecule {
76     /** A unique ID number of the molecule */
77     int64_t id;
78     /** Quaternary structure of the molecule.
79      *  1 => monomeric
80      *  2 => dimeric
81      *  3 => trimeric
82      *  etc */
83     int64_t quaternary_str;
84     /** The number of chains in the molecule */
85     int64_t n_chains;
86     /** The number of residues in the molecule */
87     int64_t n_residues;
88     /** The number of atoms in the molecule */
89     int64_t n_atoms;
90     /** The number of bonds in the molecule. If the bonds are not specified this
91      * value can be 0. */
92     int64_t n_bonds;
93     /** The name of the molecule */
94     char *name;
95     /** A list of chains in the molecule */
96     tng_chain_t chains;
97     /** A list of residues in the molecule */
98     tng_residue_t residues;
99     /** A list of the atoms in the molecule */
100     tng_atom_t atoms;
101     /** A list of the bonds in the molecule */
102     tng_bond_t bonds;
103 };
104
105 struct tng_gen_block {
106     /** The size of the block header in bytes */
107     int64_t header_contents_size;
108     /** The size of the block contents in bytes */
109     int64_t block_contents_size;
110     /** The ID of the block to determine its type */
111     int64_t id;
112     /** The MD5 hash of the block to verify integrity */
113     char md5_hash[TNG_MD5_HASH_LEN];
114     /** The name of the block */
115     char *name;
116     /** The library version used to write the block */
117     int64_t block_version;
118     int64_t alt_hash_type;
119     int64_t alt_hash_len;
120     char *alt_hash;
121     int64_t signature_type;
122     int64_t signature_len;
123     char *signature;
124     /** The full block header contents */
125     char *header_contents;
126     /** The full block contents */
127     char *block_contents;
128 };
129
130 struct tng_particle_mapping {
131     /** The index number of the first particle in this mapping block */
132     int64_t num_first_particle;
133     /** The number of particles list in this mapping block */
134     int64_t n_particles;
135     /** the mapping of index numbers to the real particle numbers in the
136      * trajectory. real_particle_numbers[0] is the real particle number
137      * (as it is numbered in the molecular system) of the first particle
138      * in the data blocks covered by this particle mapping block */
139     int64_t *real_particle_numbers;
140 };
141
142 struct tng_trajectory_frame_set {
143     /** The number of different particle mapping blocks present. */
144     int64_t n_mapping_blocks;
145     /** The atom mappings of this frame set */
146     struct tng_particle_mapping *mappings;
147     /** The first frame of this frame set */
148     int64_t first_frame;
149     /** The number of frames in this frame set */
150     int64_t n_frames;
151     /** The number of written frames in this frame set (used when writing one
152      * frame at a time). */
153     int64_t n_written_frames;
154     /** The number of frames not yet written to file in this frame set
155      * (used from the utility functions to finish the writing properly. */
156     int64_t n_unwritten_frames;
157
158
159     /** A list of the number of each molecule type - only used when using
160      * variable number of atoms */
161     int64_t *molecule_cnt_list;
162     /** The number of particles/atoms - only used when using variable number
163      * of atoms */
164     int64_t n_particles;
165     /** The file position of the next frame set */
166     int64_t next_frame_set_file_pos;
167     /** The file position of the previous frame set */
168     int64_t prev_frame_set_file_pos;
169     /** The file position of the frame set one long stride step ahead */
170     int64_t medium_stride_next_frame_set_file_pos;
171     /** The file position of the frame set one long stride step behind */
172     int64_t medium_stride_prev_frame_set_file_pos;
173     /** The file position of the frame set one long stride step ahead */
174     int64_t long_stride_next_frame_set_file_pos;
175     /** The file position of the frame set one long stride step behind */
176     int64_t long_stride_prev_frame_set_file_pos;
177     /** Time stamp (in seconds) of first frame in frame set */
178     double first_frame_time;
179
180     /* The data blocks in a frame set are trajectory data blocks */
181     /** The number of trajectory data blocks of particle dependent data */
182     int n_particle_data_blocks;
183     /** A list of data blocks containing particle dependent data */
184     struct tng_particle_data *tr_particle_data;
185     /** The number of trajectory data blocks independent of particles */
186     int n_data_blocks;
187     /** A list of data blocks containing particle indepdendent data */
188     struct tng_non_particle_data *tr_data;
189 };
190
191 /* FIXME: Should there be a pointer to a tng_gen_block from each data block? */
192 /* FIXME: Make only one data block struct */
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 2-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     /* These data blocks are non-trajectory data blocks */
356     /** The number of non-frame dependent particle dependent data blocks */
357     int n_particle_data_blocks;
358     /** A list of data blocks containing particle dependent data */
359     struct tng_particle_data *non_tr_particle_data;
360
361     /** The number of frame and particle independent data blocks */
362     int n_data_blocks;
363     /** A list of frame and particle indepdendent data blocks */
364     struct tng_non_particle_data *non_tr_data;
365
366     /** TNG compression algorithm for compressing positions */
367     int *compress_algo_pos;
368     /** TNG compression algorithm for compressing velocities */
369     int *compress_algo_vel;
370     /** The precision used for lossy compression */
371     double compression_precision;
372 };
373
374 #ifndef USE_WINDOWS
375 #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
376 #define USE_WINDOWS
377 #endif /* win32... */
378 #endif /* not defined USE_WINDOWS */
379
380 #ifdef USE_WINDOWS
381 #define TNG_INLINE __inline
382 #define TNG_SNPRINTF _snprintf
383 #else
384 #define TNG_INLINE inline
385 #define TNG_SNPRINTF snprintf
386 #endif
387
388 static TNG_INLINE int tng_min_i(int a, int b)
389 {
390     return (a < b ? a : b);
391 }
392
393 /*
394 static TNG_INLINE int tng_max_i(int a, int b)
395 {
396     return (a > b ? a : b);
397 }
398 */
399 static TNG_INLINE int64_t tng_min_i64(int64_t a, int64_t b)
400 {
401     return (a < b ? a : b);
402 }
403
404 static TNG_INLINE int64_t tng_max_i64(int64_t a, int64_t b)
405 {
406     return (a > b ? a : b);
407 }
408
409 /*
410 static TNG_INLINE float tng_min_f(float a, float b)
411 {
412     return (a < b ? a : b);
413 }
414
415 static TNG_INLINE float tng_max_f(float a, float b)
416 {
417     return (a > b ? a : b);
418 }
419
420 static TNG_INLINE double tng_min_d(double a, double b)
421 {
422     return (a < b ? a : b);
423 }
424
425 static TNG_INLINE double tng_max_d(double a, double b)
426 {
427     return (a > b ? a : b);
428 }
429 */
430
431 /** This function swaps the byte order of a 32 bit numerical variable
432  * to big endian.
433  * It does not only work with integer, but e.g. floats need casting.
434  * If the byte order is already big endian no change is needed.
435  * @param tng_data is a trajectory data container.
436  * @param v is a pointer to a 32 bit numerical value (float or integer).
437  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
438  * byte order is not recognised.
439  */
440 static tng_function_status tng_swap_byte_order_big_endian_32
441                 (const tng_trajectory_t tng_data, int32_t *v)
442 {
443     switch(tng_data->endianness_32)
444     {
445     case TNG_LITTLE_ENDIAN_32: /* Byte order is reversed. */
446         *v = ((*v & 0xFF000000) >> 24) | /* Move first byte to end */
447              ((*v & 0x00FF0000) >> 8) |  /* Move 2nd byte to pos 3 */
448              ((*v & 0x0000FF00) << 8) |  /* Move 3rd byte to pos 2 */
449              ((*v & 0x000000FF) << 24);  /* Move last byte to first */
450
451         return(TNG_SUCCESS);
452
453     case TNG_BYTE_PAIR_SWAP_32: /* byte pair swap */
454         *v = ((*v & 0xFFFF0000) >> 16) |
455              ((*v & 0x0000FFFF) << 16);
456
457         return(TNG_SUCCESS);
458
459     case TNG_BIG_ENDIAN_32: /* Already correct */
460         return(TNG_SUCCESS);
461
462     default:
463         return(TNG_FAILURE);
464     }
465 }
466
467 /** This function swaps the byte order of a 64 bit numerical variable
468  * to big endian.
469  * It does not only work with integer, but e.g. floats need casting.
470  * The byte order swapping routine can convert four different byte
471  * orders to big endian.
472  * If the byte order is already big endian no change is needed.
473  * @param tng_data is a trajectory data container.
474  * @param v is a pointer to a 64 bit numerical value (double or integer).
475  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
476  * byte order is not recognised.
477  */
478 static tng_function_status tng_swap_byte_order_big_endian_64
479                 (const tng_trajectory_t tng_data, int64_t *v)
480 {
481     switch(tng_data->endianness_64)
482     {
483     case TNG_LITTLE_ENDIAN_64: /* Byte order is reversed. */
484         *v = ((*v & 0xFF00000000000000LL) >> 56) | /* Move first byte to end */
485              ((*v & 0x00FF000000000000LL) >> 40) | /* Move 2nd byte to pos 7 */
486              ((*v & 0x0000FF0000000000LL) >> 24) | /* Move 3rd byte to pos 6 */
487              ((*v & 0x000000FF00000000LL) >> 8 ) | /* Move 4th byte to pos 5 */
488              ((*v & 0x00000000FF000000LL) << 8 ) | /* Move 5th byte to pos 4 */
489              ((*v & 0x0000000000FF0000LL) << 24) | /* Move 6th byte to pos 3 */
490              ((*v & 0x000000000000FF00LL) << 40) | /* Move 7th byte to pos 2 */
491              ((*v & 0x00000000000000FFLL) << 56);  /* Move last byte to first */
492
493         return(TNG_SUCCESS);
494
495     case TNG_QUAD_SWAP_64: /* Byte quad swap */
496         *v = ((*v & 0xFFFFFFFF00000000LL) >> 32) |
497              ((*v & 0x00000000FFFFFFFFLL) << 32);
498
499         return(TNG_SUCCESS);
500
501     case TNG_BYTE_PAIR_SWAP_64: /* Byte pair swap */
502         *v = ((*v & 0xFFFF0000FFFF0000LL) >> 16) |
503              ((*v & 0x0000FFFF0000FFFFLL) << 16);
504
505         return(TNG_SUCCESS);
506
507     case TNG_BYTE_SWAP_64: /* Byte swap */
508         *v = ((*v & 0xFF00FF00FF00FF00LL) >> 8) |
509              ((*v & 0x00FF00FF00FF00FFLL) << 8);
510
511         return(TNG_SUCCESS);
512
513     case TNG_BIG_ENDIAN_64: /* Already correct */
514         return(TNG_SUCCESS);
515
516     default:
517         return(TNG_FAILURE);
518     }
519 }
520
521 /** This function swaps the byte order of a 32 bit numerical variable
522  * to little endian.
523  * It does not only work with integer, but e.g. floats need casting.
524  * If the byte order is already little endian no change is needed.
525  * @param tng_data is a trajectory data container.
526  * @param v is a pointer to a 32 bit numerical value (float or integer).
527  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
528  * byte order is not recognised.
529  */
530 static tng_function_status tng_swap_byte_order_little_endian_32
531                 (const tng_trajectory_t tng_data, int32_t *v)
532 {
533     switch(tng_data->endianness_32)
534     {
535     case TNG_LITTLE_ENDIAN_32: /* Already correct */
536         return(TNG_SUCCESS);
537
538     case TNG_BYTE_PAIR_SWAP_32: /* byte pair swapped big endian to little endian */
539         *v = ((*v & 0xFF00FF00) >> 8) |
540              ((*v & 0x00FF00FF) << 8);
541
542         return(TNG_SUCCESS);
543
544     case TNG_BIG_ENDIAN_32: /* Byte order is reversed. */
545         *v = ((*v & 0xFF000000) >> 24) | /* Move first byte to end */
546              ((*v & 0x00FF0000) >> 8) |  /* Move 2nd byte to pos 3 */
547              ((*v & 0x0000FF00) << 8) |  /* Move 3rd byte to pos 2 */
548              ((*v & 0x000000FF) << 24);  /* Move last byte to first */
549
550         return(TNG_SUCCESS);
551
552     default:
553         return(TNG_FAILURE);
554     }
555 }
556
557 /** This function swaps the byte order of a 64 bit numerical variable
558  * to little endian.
559  * It does not only work with integer, but e.g. floats need casting.
560  * The byte order swapping routine can convert four different byte
561  * orders to little endian.
562  * If the byte order is already little endian no change is needed.
563  * @param tng_data is a trajectory data container.
564  * @param v is a pointer to a 64 bit numerical value (double or integer).
565  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
566  * byte order is not recognised.
567  */
568 static tng_function_status tng_swap_byte_order_little_endian_64
569                 (const tng_trajectory_t tng_data, int64_t *v)
570 {
571     switch(tng_data->endianness_64)
572     {
573     case TNG_LITTLE_ENDIAN_64: /* Already correct */
574         return(TNG_SUCCESS);
575
576     case TNG_QUAD_SWAP_64: /* Byte quad swapped big endian to little endian */
577         *v = ((*v & 0xFF000000FF000000LL) >> 24) |
578              ((*v & 0x00FF000000FF0000LL) >> 8) |
579              ((*v & 0x0000FF000000FF00LL) << 8) |
580              ((*v & 0x000000FF000000FFLL) << 24);
581
582         return(TNG_SUCCESS);
583
584     case TNG_BYTE_PAIR_SWAP_64: /* Byte pair swapped big endian to little endian */
585         *v = ((*v & 0xFF00FF0000000000LL) >> 40) |
586              ((*v & 0x00FF00FF00000000LL) >> 24) |
587              ((*v & 0x00000000FF00FF00LL) << 24) |
588              ((*v & 0x0000000000FF00FFLL) << 40);
589
590         return(TNG_SUCCESS);
591
592     case TNG_BYTE_SWAP_64: /* Byte swapped big endian to little endian */
593         *v = ((*v & 0xFFFF000000000000LL) >> 48) |
594              ((*v & 0x0000FFFF00000000LL) >> 16) |
595              ((*v & 0x00000000FFFF0000LL) << 16) |
596              ((*v & 0x000000000000FFFFLL) << 48);
597
598         return(TNG_SUCCESS);
599
600     case TNG_BIG_ENDIAN_64: /* Byte order is reversed. */
601         *v = ((*v & 0xFF00000000000000LL) >> 56) | /* Move first byte to end */
602              ((*v & 0x00FF000000000000LL) >> 40) | /* Move 2nd byte to pos 7 */
603              ((*v & 0x0000FF0000000000LL) >> 24) | /* Move 3rd byte to pos 6 */
604              ((*v & 0x000000FF00000000LL) >> 8 ) | /* Move 4th byte to pos 5 */
605              ((*v & 0x00000000FF000000LL) << 8 ) | /* Move 5th byte to pos 4 */
606              ((*v & 0x0000000000FF0000LL) << 24) | /* Move 6th byte to pos 3 */
607              ((*v & 0x000000000000FF00LL) << 40) | /* Move 7th byte to pos 2 */
608              ((*v & 0x00000000000000FFLL) << 56);  /* Move last byte to first */
609
610         return(TNG_SUCCESS);
611
612     default:
613         return(TNG_FAILURE);
614     }
615 }
616 /** Generate the md5 hash of a block.
617  * The hash is created based on the actual block contents.
618  * @param block is a general block container.
619  * @return TNG_SUCCESS (0) if successful.
620  */
621 static tng_function_status tng_block_md5_hash_generate(tng_gen_block_t block)
622 {
623     md5_state_t md5_state;
624
625     md5_init(&md5_state);
626     md5_append(&md5_state, (md5_byte_t *)block->block_contents,
627                (int)block->block_contents_size);
628     md5_finish(&md5_state, (md5_byte_t *)block->md5_hash);
629
630     return(TNG_SUCCESS);
631 }
632
633 /** Compare the current block md5 hash (e.g. read from file) with the md5 hash
634  * calculated from the current contents.
635  * If the current md5 hash is not set skip the comparison.
636  * @param block is a general block container.
637  * @param results If the hashes match results is set to TNG_TRUE, otherwise it is
638  * set to TNG_FALSE. If the hash was not set results is set to TNG_TRUE.
639  * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the hash was not
640  * set.
641  */
642 static tng_function_status tng_md5_hash_match_verify(tng_gen_block_t block,
643                                                      tng_bool *results)
644 {
645     md5_state_t md5_state;
646     char hash[TNG_MD5_HASH_LEN];
647
648     TNG_ASSERT(block->block_contents_size > 0, "The block contents size must be > 0");
649
650     *results = TNG_TRUE;
651     if(strncmp(block->md5_hash, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) == 0)
652     {
653         return(TNG_FAILURE);
654     }
655     md5_init(&md5_state);
656     md5_append(&md5_state, (md5_byte_t *)block->block_contents,
657                (int)block->block_contents_size);
658     md5_finish(&md5_state, (md5_byte_t *)hash);
659
660     if(strncmp(block->md5_hash, hash, 16) != 0)
661     {
662         *results = TNG_FALSE;
663     }
664
665     return(TNG_SUCCESS);
666 }
667
668 /** Open the input file if it is not already opened.
669  * @param tng_data is a trajectory data container.
670  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
671  * error has occured.
672  */
673 static tng_function_status tng_input_file_init(tng_trajectory_t tng_data)
674 {
675     if(!tng_data->input_file)
676     {
677         if(!tng_data->input_file_path)
678         {
679             fprintf(stderr, "TNG library: No file specified for reading. %s: %d\n",
680                    __FILE__, __LINE__);
681             return(TNG_CRITICAL);
682         }
683         tng_data->input_file = fopen(tng_data->input_file_path, "rb");
684         if(!tng_data->input_file)
685         {
686             fprintf(stderr, "TNG library: Cannot open file %s. %s: %d\n",
687                    tng_data->input_file_path, __FILE__, __LINE__);
688             return(TNG_CRITICAL);
689         }
690     }
691     return(TNG_SUCCESS);
692 }
693
694 /** Open the output file if it is not already opened
695  * @param tng_data is a trajectory data container.
696  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
697  * error has occured.
698  */
699 static tng_function_status tng_output_file_init(tng_trajectory_t tng_data)
700 {
701     if(!tng_data->output_file)
702     {
703         if(!tng_data->output_file_path)
704         {
705             fprintf(stderr, "TNG library: No file specified for writing. %s: %d\n",
706                    __FILE__, __LINE__);
707             return(TNG_CRITICAL);
708         }
709
710         tng_data->output_file = fopen(tng_data->output_file_path, "wb+");
711
712         if(!tng_data->output_file)
713         {
714             fprintf(stderr, "TNG library: Cannot open file %s. %s: %d\n",
715                    tng_data->output_file_path, __FILE__, __LINE__);
716             return(TNG_CRITICAL);
717         }
718     }
719     return(TNG_SUCCESS);
720 }
721
722 /** Setup a file block container.
723  * @param block_p a pointer to memory to initialise as a file block container.
724  * @details Memory is allocated during initialisation.
725  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
726  * error has occured.
727  */
728 static tng_function_status tng_block_init(struct tng_gen_block **block_p)
729 {
730     tng_gen_block_t block;
731
732     *block_p = malloc(sizeof(struct tng_gen_block));
733     if(!*block_p)
734     {
735         fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
736                sizeof(struct tng_gen_block), __FILE__, __LINE__);
737         return(TNG_CRITICAL);
738     }
739
740     block = *block_p;
741
742     block->id = -1;
743     /* Reset the md5_hash */
744     memcpy(block->md5_hash, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", TNG_MD5_HASH_LEN);
745     block->name = 0;
746     block->block_version = TNG_API_VERSION;
747     block->header_contents = 0;
748     block->header_contents_size = 0;
749     block->block_contents = 0;
750     block->block_contents_size = 0;
751
752     return(TNG_SUCCESS);
753 }
754
755 /**
756  * @brief Clean up a file block container.
757  * @param block_p a pointer to the file block container to destroy.
758  * @details All allocated memory in the data structure is freed, as well as
759  * block_p itself.
760  * @return TNG_SUCCESS (0) if successful.
761  */
762 static tng_function_status tng_block_destroy(struct tng_gen_block **block_p)
763 {
764     tng_gen_block_t block = *block_p;
765
766     if(!*block_p)
767     {
768         return(TNG_SUCCESS);
769     }
770
771 /*     fprintf(stderr, "TNG library: Destroying block\n"); */
772     if(block->name)
773     {
774         free(block->name);
775         block->name = 0;
776     }
777     if(block->header_contents)
778     {
779         free(block->header_contents);
780         block->header_contents = 0;
781     }
782     if(block->block_contents)
783     {
784         free(block->block_contents);
785         block->block_contents = 0;
786     }
787
788     free(*block_p);
789     *block_p = 0;
790
791     return(TNG_SUCCESS);
792 }
793
794 /** Read the header of a data block, regardless of its type
795  * @param tng_data is a trajectory data container.
796  * @param block is a general block container.
797  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE(1) if a minor
798  * error has occured (not able to read the header size, thus skipping
799  * the block) or TNG_CRITICAL (2) if a major error has occured.
800  */
801 static tng_function_status tng_block_header_read
802                 (tng_trajectory_t tng_data, tng_gen_block_t block)
803 {
804     int len, offset = 0;
805
806     TNG_ASSERT(block != 0, "TNG library: Trying to read to uninitialized block (NULL pointer).");
807
808     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
809     {
810         return(TNG_CRITICAL);
811     }
812
813     /* First read the header size to be able to read the whole header. */
814     if(fread(&block->header_contents_size, sizeof(block->header_contents_size),
815         1, tng_data->input_file) == 0)
816     {
817         fprintf(stderr, "TNG library: Cannot read header size. %s: %d\n",
818                __FILE__, __LINE__);
819         return(TNG_CRITICAL);
820     }
821
822     if(block->header_contents_size == 0)
823     {
824         block->id = -1;
825         return(TNG_FAILURE);
826     }
827
828     /* If this was the size of the general info block check the endianness */
829     if(ftell(tng_data->input_file) < 9)
830     {
831         /* File is little endian */
832         if ( *((const char*)&block->header_contents_size) != 0x00 &&
833              *((const char*)(&block->header_contents_size) + 7) == 0x00)
834         {
835             /* If the architecture endianness is little endian no byte swap
836              * will be needed. Otherwise use the functions to swap to little
837              * endian */
838             if(tng_data->endianness_32 == TNG_LITTLE_ENDIAN_32)
839             {
840                 tng_data->input_endianness_swap_func_32 = 0;
841             }
842             else
843             {
844                 tng_data->input_endianness_swap_func_32 =
845                 &tng_swap_byte_order_little_endian_32;
846             }
847             if(tng_data->endianness_64 == TNG_LITTLE_ENDIAN_64)
848             {
849                 tng_data->input_endianness_swap_func_64 = 0;
850             }
851             else
852             {
853                 tng_data->input_endianness_swap_func_64 =
854                 &tng_swap_byte_order_little_endian_64;
855             }
856         }
857         /* File is big endian */
858         else
859         {
860             /* If the architecture endianness is big endian no byte swap
861              * will be needed. Otherwise use the functions to swap to big
862              * endian */
863             if(tng_data->endianness_32 == TNG_BIG_ENDIAN_32)
864             {
865                 tng_data->input_endianness_swap_func_32 = 0;
866             }
867             else
868             {
869                 tng_data->input_endianness_swap_func_32 =
870                 &tng_swap_byte_order_big_endian_32;
871             }
872             if(tng_data->endianness_64 == TNG_BIG_ENDIAN_64)
873             {
874                 tng_data->input_endianness_swap_func_64 = 0;
875             }
876             else
877             {
878                 tng_data->input_endianness_swap_func_64 =
879                 &tng_swap_byte_order_big_endian_64;
880             }
881         }
882     }
883
884     if(tng_data->input_endianness_swap_func_64)
885     {
886         if(tng_data->input_endianness_swap_func_64(tng_data,
887                                                    &block->header_contents_size)
888             != TNG_SUCCESS)
889         {
890             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
891                     __FILE__, __LINE__);
892         }
893     }
894
895     /* Move the reading position to the beginning of the header. */
896     fseek(tng_data->input_file, -(long)sizeof(block->header_contents_size),
897           SEEK_CUR);
898
899     /* If there is already memory allocated for the contents free it (we do not
900      * know if the size is correct). */
901     if(block->header_contents)
902     {
903         free(block->header_contents);
904     }
905
906     block->header_contents = malloc(block->header_contents_size);
907     if(!block->header_contents)
908     {
909         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
910                block->header_contents_size, __FILE__, __LINE__);
911         return(TNG_CRITICAL);
912     }
913
914     /* Read the whole header into header_contents. This way it can be saved
915      * even if it cannot be interpreted
916      * for one reason or another. */
917     if(fread(block->header_contents, block->header_contents_size, 1,
918         tng_data->input_file) == 0)
919     {
920         fprintf(stderr, "TNG library: Cannot read header. %s: %d\n", __FILE__, __LINE__);
921         return(TNG_CRITICAL);
922     }
923
924     /* The header contents size has already been read. Skip ahead. */
925     offset = sizeof(block->header_contents_size);
926
927
928     /* Copy the respective parameters from the header contents block */
929     memcpy(&block->block_contents_size, block->header_contents+offset,
930            sizeof(block->block_contents_size));
931     if(tng_data->input_endianness_swap_func_64)
932     {
933         if(tng_data->input_endianness_swap_func_64(tng_data,
934                                                    &block->block_contents_size)
935             != TNG_SUCCESS)
936         {
937             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
938                     __FILE__, __LINE__);
939         }
940     }
941
942     offset += sizeof(block->block_contents_size);
943
944     memcpy(&block->id, block->header_contents+offset, sizeof(block->id));
945     if(tng_data->input_endianness_swap_func_64)
946     {
947         if(tng_data->input_endianness_swap_func_64(tng_data,
948                                                    &block->id)
949             != TNG_SUCCESS)
950         {
951             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
952                     __FILE__, __LINE__);
953         }
954     }
955
956     offset += sizeof(block->id);
957
958     memcpy(block->md5_hash, block->header_contents+offset, TNG_MD5_HASH_LEN);
959     offset += TNG_MD5_HASH_LEN;
960
961     if(block->name && strcmp(block->name, block->header_contents+offset) != 0)
962     {
963         free(block->name);
964         block->name = 0;
965     }
966     len = tng_min_i((int)strlen(block->header_contents+offset) + 1, TNG_MAX_STR_LEN);
967     if(!block->name)
968     {
969         block->name = malloc(len);
970         if(!block->name)
971         {
972             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
973                     __FILE__, __LINE__);
974             return(TNG_CRITICAL);
975         }
976         strncpy(block->name, block->header_contents+offset, len);
977     }
978     offset += len;
979
980     memcpy(&block->block_version, block->header_contents+offset,
981            sizeof(block->block_version));
982     if(tng_data->input_endianness_swap_func_64)
983     {
984         if(tng_data->input_endianness_swap_func_64(tng_data,
985                                                    &block->block_version)
986             != TNG_SUCCESS)
987         {
988             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
989                     __FILE__, __LINE__);
990         }
991     }
992
993     return(TNG_SUCCESS);
994 }
995
996 /** Write a whole block, both header and contents, regardless of it type
997  * @param tng_data is a trajectory data container.
998  * @param block is a general block container.
999  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
1000  * has occurred or TNG_CRITICAL (2) if a major error has occured.
1001  */
1002 /* Disabled until it is used.*/
1003 /*
1004 // static tng_function_status tng_block_verbatim_write(tng_trajectory_t tng_data,
1005 //                                                     tng_gen_block_t block)
1006 // {
1007 //     if(!block->header_contents)
1008 //     {
1009 //         fprintf(stderr, "TNG library: No contents to write. %s: %d\n", __FILE__, __LINE__);
1010 //         return(TNG_FAILURE);
1011 //     }
1012 //     if(fwrite(block->header_contents, block->header_contents_size, 1,
1013 //                 tng_data->output_file) != 1)
1014 //     {
1015 //         fprintf(stderr, "TNG library: Could not write all header data. %s: %d\n",
1016 //                 __FILE__, __LINE__);
1017 //         return(TNG_CRITICAL);
1018 //     }
1019 //
1020 //     if(!block->block_contents)
1021 //     {
1022 //         fprintf(stderr, "TNG library: No block data to write. %s: %d\n",
1023 //                 __FILE__, __LINE__);
1024 //         return(TNG_FAILURE);
1025 //     }
1026 //     if(fwrite(block->block_contents, block->block_contents_size, 1,
1027 //                 tng_data->output_file) != 1)
1028 //     {
1029 //         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n",
1030 //                 __FILE__, __LINE__);
1031 //         return(TNG_CRITICAL);
1032 //     }
1033 //     return(TNG_SUCCESS);
1034 // }
1035 */
1036
1037 /** Update the md5 hash of a block already written to the file
1038  * @param tng_data is a trajectory data container.
1039  * @param block is the block, of which to update the md5 hash.
1040  * @param header_start_pos is the file position where the block header starts.
1041  * @param contents_start_pos is the file position where the block contents
1042  * start.
1043  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
1044  * error has occured.
1045  */
1046 static tng_function_status tng_md5_hash_update(tng_trajectory_t tng_data,
1047                                                tng_gen_block_t block,
1048                                                const int64_t header_start_pos,
1049                                                const int64_t contents_start_pos)
1050 {
1051     if(block->block_contents)
1052     {
1053         free(block->block_contents);
1054     }
1055
1056     block->block_contents = malloc(block->block_contents_size);
1057     if(!block->block_contents)
1058     {
1059         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
1060                block->block_contents_size, __FILE__, __LINE__);
1061         return(TNG_CRITICAL);
1062     }
1063
1064     fseek(tng_data->output_file, (long)contents_start_pos, SEEK_SET);
1065     if(fread(block->block_contents, block->block_contents_size, 1,
1066             tng_data->output_file) == 0)
1067     {
1068         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
1069         return(TNG_CRITICAL);
1070     }
1071
1072     tng_block_md5_hash_generate(block);
1073
1074     fseek(tng_data->output_file, (long)header_start_pos + 3 * sizeof(int64_t),
1075           SEEK_SET);
1076     fwrite(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->output_file);
1077
1078     return(TNG_SUCCESS);
1079 }
1080
1081 /** Update the frame set pointers in the file header (general info block),
1082  * already written to disk
1083  * @param tng_data is a trajectory data container.
1084  * @param hash_mode specifies whether to update the block md5 hash when
1085  * updating the pointers.
1086  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
1087  * error has occured.
1088  */
1089 static tng_function_status tng_header_pointers_update
1090                 (tng_trajectory_t tng_data, const char hash_mode)
1091 {
1092     tng_gen_block_t block;
1093     FILE *temp = tng_data->input_file;
1094     int64_t output_file_pos, pos, contents_start_pos;
1095
1096     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
1097     {
1098         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
1099                __FILE__, __LINE__);
1100         return(TNG_CRITICAL);
1101     }
1102
1103     tng_data->input_file = tng_data->output_file;
1104
1105     tng_block_init(&block);
1106
1107     output_file_pos = ftell(tng_data->output_file);
1108     fseek(tng_data->output_file, 0, SEEK_SET);
1109
1110     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1111     {
1112         fprintf(stderr, "TNG library: Cannot read general info header. %s: %d\n",
1113                __FILE__, __LINE__);
1114         tng_data->input_file = temp;
1115         tng_block_destroy(&block);
1116         return(TNG_CRITICAL);
1117     }
1118
1119     contents_start_pos = ftell(tng_data->output_file);
1120
1121     fseek(tng_data->output_file, (long)block->block_contents_size - 5 *
1122           sizeof(int64_t), SEEK_CUR);
1123
1124     tng_data->input_file = temp;
1125
1126     pos = tng_data->first_trajectory_frame_set_output_file_pos;
1127
1128     if(tng_data->input_endianness_swap_func_64)
1129     {
1130         if(tng_data->input_endianness_swap_func_64(tng_data,
1131                                                     &pos)
1132             != TNG_SUCCESS)
1133         {
1134             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1135                     __FILE__, __LINE__);
1136         }
1137     }
1138
1139     if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1140     {
1141         tng_block_destroy(&block);
1142         return(TNG_CRITICAL);
1143     }
1144
1145     pos = tng_data->last_trajectory_frame_set_output_file_pos;
1146
1147     if(tng_data->input_endianness_swap_func_64)
1148     {
1149         if(tng_data->input_endianness_swap_func_64(tng_data,
1150                                                     &pos)
1151             != TNG_SUCCESS)
1152         {
1153             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1154                     __FILE__, __LINE__);
1155         }
1156     }
1157
1158     if(fwrite(&pos,
1159         sizeof(int64_t), 1, tng_data->output_file) != 1)
1160     {
1161         tng_block_destroy(&block);
1162         return(TNG_CRITICAL);
1163     }
1164
1165     if(hash_mode == TNG_USE_HASH)
1166     {
1167         tng_md5_hash_update(tng_data, block, 0, contents_start_pos);
1168     }
1169
1170     tng_block_destroy(&block);
1171
1172     fseek(tng_data->output_file, (long)output_file_pos, SEEK_SET);
1173
1174     return(TNG_SUCCESS);
1175 }
1176
1177 /** Update the frame set pointers in the current frame set block, already
1178  * written to disk. It also updates the pointers of the blocks pointing to
1179  * the current frame set block.
1180  * @param tng_data is a trajectory data container.
1181  * @param hash_mode specifies whether to update the block md5 hash when
1182  * updating the pointers.
1183  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
1184  * error has occured.
1185  */
1186 static tng_function_status tng_frame_set_pointers_update
1187                 (tng_trajectory_t tng_data, const char hash_mode)
1188 {
1189     tng_gen_block_t block;
1190     tng_trajectory_frame_set_t frame_set;
1191     FILE *temp = tng_data->input_file;
1192     int64_t pos, output_file_pos, contents_start_pos;
1193
1194     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
1195     {
1196         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
1197                __FILE__, __LINE__);
1198         return(TNG_CRITICAL);
1199     }
1200
1201     tng_block_init(&block);
1202     output_file_pos = ftell(tng_data->output_file);
1203
1204     tng_data->input_file = tng_data->output_file;
1205
1206     frame_set = &tng_data->current_trajectory_frame_set;
1207
1208     pos = tng_data->current_trajectory_frame_set_output_file_pos;
1209
1210     /* Update next frame set */
1211     if(frame_set->next_frame_set_file_pos > 0)
1212     {
1213         fseek(tng_data->output_file, (long)frame_set->next_frame_set_file_pos,
1214               SEEK_SET);
1215
1216         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1217         {
1218             fprintf(stderr, "TNG library: Cannot read frame header. %s: %d\n",
1219                 __FILE__, __LINE__);
1220             tng_data->input_file = temp;
1221             tng_block_destroy(&block);
1222             return(TNG_CRITICAL);
1223         }
1224
1225         contents_start_pos = ftell(tng_data->output_file);
1226
1227         fseek(tng_data->output_file, (long)block->block_contents_size - (5 *
1228             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1229
1230         if(tng_data->input_endianness_swap_func_64)
1231         {
1232             if(tng_data->input_endianness_swap_func_64(tng_data,
1233                                                         &pos)
1234                 != TNG_SUCCESS)
1235             {
1236                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1237                         __FILE__, __LINE__);
1238             }
1239         }
1240
1241         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1242         {
1243             tng_data->input_file = temp;
1244             tng_block_destroy(&block);
1245             return(TNG_CRITICAL);
1246         }
1247
1248         if(hash_mode == TNG_USE_HASH)
1249         {
1250             tng_md5_hash_update(tng_data, block, frame_set->next_frame_set_file_pos,
1251                                 contents_start_pos);
1252         }
1253         fseek(tng_data->output_file, (long)output_file_pos, SEEK_SET);
1254     }
1255     /* Update previous frame set */
1256     if(frame_set->prev_frame_set_file_pos > 0)
1257     {
1258         fseek(tng_data->output_file, (long)frame_set->prev_frame_set_file_pos,
1259               SEEK_SET);
1260
1261         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1262         {
1263             fprintf(stderr, "TNG library: Cannot read frame header. %s: %d\n",
1264                 __FILE__, __LINE__);
1265             tng_data->input_file = temp;
1266             tng_block_destroy(&block);
1267             return(TNG_CRITICAL);
1268         }
1269
1270         contents_start_pos = ftell(tng_data->output_file);
1271
1272         fseek(tng_data->output_file, (long)block->block_contents_size - (6 *
1273             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1274
1275         if(tng_data->input_endianness_swap_func_64)
1276         {
1277             if(tng_data->input_endianness_swap_func_64(tng_data,
1278                                                         &pos)
1279                 != TNG_SUCCESS)
1280             {
1281                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1282                         __FILE__, __LINE__);
1283             }
1284         }
1285
1286         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1287         {
1288             tng_data->input_file = temp;
1289             tng_block_destroy(&block);
1290             return(TNG_CRITICAL);
1291         }
1292
1293         if(hash_mode == TNG_USE_HASH)
1294         {
1295             tng_md5_hash_update(tng_data, block, frame_set->prev_frame_set_file_pos,
1296                                 contents_start_pos);
1297         }
1298         fseek(tng_data->output_file, (long)output_file_pos, SEEK_SET);
1299     }
1300
1301     /* Update the frame set one medium stride step after */
1302     if(frame_set->medium_stride_next_frame_set_file_pos > 0)
1303     {
1304         fseek(tng_data->output_file,
1305               (long)frame_set->medium_stride_next_frame_set_file_pos,
1306               SEEK_SET);
1307
1308         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1309         {
1310             fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
1311                 __FILE__, __LINE__);
1312             tng_data->input_file = temp;
1313             tng_block_destroy(&block);
1314             return(TNG_CRITICAL);
1315         }
1316
1317         contents_start_pos = ftell(tng_data->output_file);
1318
1319         fseek(tng_data->output_file, (long)block->block_contents_size - (3 *
1320             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1321
1322         if(tng_data->input_endianness_swap_func_64)
1323         {
1324             if(tng_data->input_endianness_swap_func_64(tng_data,
1325                                                         &pos)
1326                 != TNG_SUCCESS)
1327             {
1328                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1329                         __FILE__, __LINE__);
1330             }
1331         }
1332
1333         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1334         {
1335             tng_data->input_file = temp;
1336             tng_block_destroy(&block);
1337             return(TNG_CRITICAL);
1338         }
1339
1340         if(hash_mode == TNG_USE_HASH)
1341         {
1342             tng_md5_hash_update(tng_data, block,
1343                                 frame_set->medium_stride_next_frame_set_file_pos,
1344                                 contents_start_pos);
1345         }
1346     }
1347     /* Update the frame set one medium stride step before */
1348     if(frame_set->medium_stride_prev_frame_set_file_pos > 0)
1349     {
1350         fseek(tng_data->output_file,
1351               (long)frame_set->medium_stride_prev_frame_set_file_pos,
1352               SEEK_SET);
1353
1354         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1355         {
1356             fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
1357                 __FILE__, __LINE__);
1358             tng_data->input_file = temp;
1359             tng_block_destroy(&block);
1360             return(TNG_CRITICAL);
1361         }
1362
1363         contents_start_pos = ftell(tng_data->output_file);
1364
1365         fseek(tng_data->output_file, (long)block->block_contents_size - (4 *
1366             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1367
1368         if(tng_data->input_endianness_swap_func_64)
1369         {
1370             if(tng_data->input_endianness_swap_func_64(tng_data,
1371                                                         &pos)
1372                 != TNG_SUCCESS)
1373             {
1374                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1375                         __FILE__, __LINE__);
1376             }
1377         }
1378
1379         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1380         {
1381             tng_data->input_file = temp;
1382             tng_block_destroy(&block);
1383             return(TNG_CRITICAL);
1384         }
1385
1386         if(hash_mode == TNG_USE_HASH)
1387         {
1388             tng_md5_hash_update(tng_data, block,
1389                                 frame_set->medium_stride_prev_frame_set_file_pos,
1390                                 contents_start_pos);
1391         }
1392     }
1393
1394     /* Update the frame set one long stride step after */
1395     if(frame_set->long_stride_next_frame_set_file_pos > 0)
1396     {
1397         fseek(tng_data->output_file,
1398               (long)frame_set->long_stride_next_frame_set_file_pos,
1399               SEEK_SET);
1400
1401         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1402         {
1403             fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
1404                 __FILE__, __LINE__);
1405             tng_data->input_file = temp;
1406             tng_block_destroy(&block);
1407             return(TNG_CRITICAL);
1408         }
1409
1410         contents_start_pos = ftell(tng_data->output_file);
1411
1412         fseek(tng_data->output_file, (long)block->block_contents_size - (1 *
1413             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1414
1415         if(tng_data->input_endianness_swap_func_64)
1416         {
1417             if(tng_data->input_endianness_swap_func_64(tng_data,
1418                                                         &pos)
1419                 != TNG_SUCCESS)
1420             {
1421                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1422                         __FILE__, __LINE__);
1423             }
1424         }
1425
1426         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1427         {
1428             tng_data->input_file = temp;
1429             tng_block_destroy(&block);
1430             return(TNG_CRITICAL);
1431         }
1432
1433         if(hash_mode == TNG_USE_HASH)
1434         {
1435             tng_md5_hash_update(tng_data, block,
1436                                 frame_set->long_stride_next_frame_set_file_pos,
1437                                 contents_start_pos);
1438         }
1439     }
1440     /* Update the frame set one long stride step before */
1441     if(frame_set->long_stride_prev_frame_set_file_pos > 0)
1442     {
1443         fseek(tng_data->output_file,
1444               (long)frame_set->long_stride_prev_frame_set_file_pos,
1445               SEEK_SET);
1446
1447         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1448         {
1449             fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
1450                 __FILE__, __LINE__);
1451             tng_data->input_file = temp;
1452             tng_block_destroy(&block);
1453             return(TNG_CRITICAL);
1454         }
1455
1456         contents_start_pos = ftell(tng_data->output_file);
1457
1458         fseek(tng_data->output_file, (long)block->block_contents_size - (2 *
1459             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1460
1461         if(tng_data->input_endianness_swap_func_64)
1462         {
1463             if(tng_data->input_endianness_swap_func_64(tng_data,
1464                                                         &pos)
1465                 != TNG_SUCCESS)
1466             {
1467                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1468                         __FILE__, __LINE__);
1469             }
1470         }
1471
1472         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1473         {
1474             tng_data->input_file = temp;
1475             tng_block_destroy(&block);
1476             return(TNG_CRITICAL);
1477         }
1478
1479         if(hash_mode == TNG_USE_HASH)
1480         {
1481             tng_md5_hash_update(tng_data, block,
1482                                 frame_set->long_stride_prev_frame_set_file_pos,
1483                                 contents_start_pos);
1484         }
1485     }
1486
1487     fseek(tng_data->output_file, (long)output_file_pos, SEEK_SET);
1488
1489     tng_data->input_file = temp;
1490
1491     tng_block_destroy(&block);
1492
1493     return(TNG_SUCCESS);
1494 }
1495
1496 static tng_function_status tng_reread_frame_set_at_file_pos
1497                 (tng_trajectory_t tng_data,
1498                  const int64_t pos)
1499 {
1500     tng_gen_block_t block;
1501     tng_function_status stat;
1502
1503     tng_block_init(&block);
1504
1505     fseek(tng_data->input_file, pos, SEEK_SET);
1506     if(pos > 0)
1507     {
1508         stat = tng_block_header_read(tng_data, block);
1509         if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
1510         {
1511             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", pos,
1512                     __FILE__, __LINE__);
1513             tng_block_destroy(&block);
1514             return(TNG_FAILURE);
1515         }
1516
1517         if(tng_block_read_next(tng_data, block,
1518                                TNG_SKIP_HASH) != TNG_SUCCESS)
1519         {
1520             tng_block_destroy(&block);
1521             return(TNG_CRITICAL);
1522         }
1523     }
1524
1525     tng_block_destroy(&block);
1526
1527     return(TNG_SUCCESS);
1528 }
1529
1530 static tng_function_status tng_file_pos_of_subsequent_trajectory_block_get
1531                 (tng_trajectory_t tng_data,
1532                  int64_t *pos)
1533 {
1534     int64_t orig_pos, curr_frame_set_pos;
1535     tng_gen_block_t block;
1536     tng_function_status stat;
1537     tng_trajectory_frame_set_t frame_set =
1538     &tng_data->current_trajectory_frame_set;
1539
1540     orig_pos = ftell(tng_data->input_file);
1541     curr_frame_set_pos = tng_data->current_trajectory_frame_set_input_file_pos;
1542
1543     *pos = tng_data->first_trajectory_frame_set_input_file_pos;
1544
1545     if(*pos <= 0)
1546     {
1547         return(TNG_SUCCESS);
1548     }
1549
1550     fseek(tng_data->input_file, *pos, SEEK_SET);
1551
1552     tng_block_init(&block);
1553     /* Read block headers first to see that a frame set block is found. */
1554     stat = tng_block_header_read(tng_data, block);
1555     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
1556     {
1557         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", *pos,
1558                 __FILE__, __LINE__);
1559         tng_block_destroy(&block);
1560         return(TNG_FAILURE);
1561     }
1562
1563     if(tng_block_read_next(tng_data, block,
1564                            TNG_SKIP_HASH) != TNG_SUCCESS)
1565     {
1566         tng_block_destroy(&block);
1567         return(TNG_CRITICAL);
1568     }
1569
1570     /* Read all frame set blocks (not the blocks between them) */
1571     while(frame_set->next_frame_set_file_pos > 0)
1572     {
1573         fseek(tng_data->input_file, frame_set->next_frame_set_file_pos, SEEK_SET);
1574         stat = tng_block_header_read(tng_data, block);
1575         if(stat == TNG_CRITICAL)
1576         {
1577             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", *pos,
1578                     __FILE__, __LINE__);
1579             tng_block_destroy(&block);
1580             return(TNG_CRITICAL);
1581         }
1582         if(stat != TNG_SUCCESS || block->id != TNG_TRAJECTORY_FRAME_SET)
1583         {
1584             return(TNG_FAILURE);
1585         }
1586
1587         stat = tng_block_read_next(tng_data, block, TNG_SKIP_HASH);
1588         if(stat != TNG_SUCCESS)
1589         {
1590             tng_block_destroy(&block);
1591             return(stat);
1592         }
1593         /* Update *pos if this is the earliest frame set so far (after orig_pos) */
1594         if(tng_data->current_trajectory_frame_set_input_file_pos < *pos &&
1595            tng_data->current_trajectory_frame_set_input_file_pos > orig_pos)
1596         {
1597             *pos = tng_data->current_trajectory_frame_set_input_file_pos;
1598         }
1599     }
1600
1601     /* Re-read the frame set that used to be the current one */
1602     tng_reread_frame_set_at_file_pos(tng_data, curr_frame_set_pos);
1603
1604     fseek(tng_data->input_file, orig_pos, SEEK_SET);
1605
1606     tng_block_destroy(&block);
1607
1608     return(TNG_SUCCESS);
1609 }
1610
1611 static tng_function_status tng_frame_set_complete_migrate
1612                 (tng_trajectory_t tng_data,
1613                  int64_t block_start_pos,
1614                  int64_t block_len,
1615                  int64_t new_pos)
1616 {
1617     int64_t i;
1618     tng_bool updated = TNG_FALSE;
1619
1620     char *contents;
1621
1622     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
1623     {
1624         return(TNG_CRITICAL);
1625     }
1626
1627     fseek(tng_data->input_file, block_start_pos, SEEK_SET);
1628
1629     contents = malloc(block_len);
1630     if(!contents)
1631     {
1632         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
1633                 block_len, __FILE__, __LINE__);
1634         return(TNG_CRITICAL);
1635     }
1636
1637     if(fread(contents, block_len, 1, tng_data->input_file) == 0)
1638     {
1639         fprintf(stderr, "TNG library: Cannot read data from file when migrating data. %s: %d\n",
1640                __FILE__, __LINE__);
1641         free(contents);
1642         return(TNG_CRITICAL);
1643     }
1644     fseek(tng_data->output_file, new_pos, SEEK_SET);
1645
1646     if(fwrite(contents, block_len, 1, tng_data->output_file) != 1)
1647     {
1648         fprintf(stderr, "TNG library: Could not write data to file when migrating data. %s: %d\n",
1649                 __FILE__, __LINE__);
1650         free(contents);
1651         return(TNG_CRITICAL);
1652     }
1653
1654     tng_data->current_trajectory_frame_set_output_file_pos = new_pos;
1655
1656     tng_frame_set_pointers_update(tng_data, TNG_USE_HASH);
1657
1658     /* Update the general info block if needed */
1659     if(block_start_pos == tng_data->first_trajectory_frame_set_output_file_pos)
1660     {
1661         tng_data->first_trajectory_frame_set_output_file_pos = new_pos;
1662         updated = TNG_TRUE;
1663     }
1664     if(block_start_pos == tng_data->last_trajectory_frame_set_output_file_pos)
1665     {
1666         tng_data->last_trajectory_frame_set_output_file_pos = new_pos;
1667         updated = TNG_TRUE;
1668     }
1669     if(updated)
1670     {
1671         tng_header_pointers_update(tng_data, TNG_USE_HASH);
1672     }
1673
1674     /* Fill the block with NULL to avoid confusion. */
1675     for(i = 0; i < block_len; i++)
1676     {
1677         contents[i] = '\0';
1678     }
1679     fseek(tng_data->output_file, block_start_pos, SEEK_SET);
1680
1681     /* FIXME: casting block_len to size_t is dangerous */
1682     fwrite(contents, 1, block_len, tng_data->output_file);
1683
1684     free(contents);
1685
1686     return(TNG_SUCCESS);
1687 }
1688
1689 static tng_function_status tng_length_of_current_frame_set_contents_get
1690                 (tng_trajectory_t tng_data,
1691                  int64_t *len)
1692 {
1693     int64_t orig_pos, pos, curr_frame_set_pos;
1694     tng_gen_block_t block;
1695     tng_function_status stat;
1696
1697     orig_pos = ftell(tng_data->input_file);
1698     curr_frame_set_pos = pos = tng_data->current_trajectory_frame_set_input_file_pos;
1699
1700     *len = 0;
1701
1702     fseek(tng_data->input_file, curr_frame_set_pos, SEEK_SET);
1703
1704     tng_block_init(&block);
1705     /* Read block headers first to see that a frame set block is found. */
1706     stat = tng_block_header_read(tng_data, block);
1707     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
1708     {
1709         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
1710                 curr_frame_set_pos, __FILE__, __LINE__);
1711         tng_block_destroy(&block);
1712         return(TNG_FAILURE);
1713     }
1714
1715     /* Read the headers of all blocks in the frame set (not the actual contents of them) */
1716     while(stat == TNG_SUCCESS)
1717     {
1718         fseek(tng_data->input_file, block->block_contents_size, SEEK_CUR);
1719         *len += block->header_contents_size + block->block_contents_size;
1720         pos += block->header_contents_size + block->block_contents_size;
1721         if(pos >= tng_data->input_file_len)
1722         {
1723             break;
1724         }
1725         stat = tng_block_header_read(tng_data, block);
1726         if(block->id == TNG_TRAJECTORY_FRAME_SET)
1727         {
1728             break;
1729         }
1730     }
1731
1732     /* Re-read the frame set that used to be the current one */
1733     tng_reread_frame_set_at_file_pos(tng_data, curr_frame_set_pos);
1734
1735     fseek(tng_data->input_file, orig_pos, SEEK_SET);
1736
1737     tng_block_destroy(&block);
1738
1739     return(TNG_SUCCESS);
1740 }
1741
1742 /** Migrate blocks in the file to make room for new data in a block. This
1743  * is required e.g. when adding data to a block or extending strings in a
1744  * block.
1745  * @param tng_data is a trajectory data container.
1746  * @param start_pos is the position from which to start moving data, usually
1747  * the byte after the end of the block to which data was added.
1748  * @param offset is the number of bytes that were inserted.
1749  * @details Trajectory blocks (frame sets and their related blocks) are moved
1750  * to the end of the file (if needed) in order to make room for non-trajectory
1751  * data.
1752  */
1753 static tng_function_status tng_migrate_data_in_file
1754                 (tng_trajectory_t tng_data,
1755                  int64_t start_pos,
1756                  int64_t offset)
1757 {
1758     int64_t traj_start_pos, empty_space, orig_file_pos, frame_set_length;
1759     tng_gen_block_t block;
1760     tng_function_status stat;
1761     FILE *temp;
1762
1763     if(offset <= 0)
1764     {
1765         return(TNG_SUCCESS);
1766     }
1767
1768     temp = tng_data->input_file;
1769
1770     stat = tng_file_pos_of_subsequent_trajectory_block_get(tng_data, &traj_start_pos);
1771     if(stat != TNG_SUCCESS)
1772     {
1773         tng_data->input_file = temp;
1774         return(stat);
1775     }
1776
1777     tng_data->current_trajectory_frame_set_input_file_pos = traj_start_pos;
1778
1779     empty_space = traj_start_pos - (start_pos - 1);
1780
1781     if(empty_space >= offset)
1782     {
1783         return(TNG_SUCCESS);
1784     }
1785
1786     orig_file_pos = ftell(tng_data->input_file);
1787     tng_block_init(&block);
1788
1789     while(empty_space < offset)
1790     {
1791         fseek(tng_data->input_file, traj_start_pos, SEEK_SET);
1792         stat = tng_block_header_read(tng_data, block);
1793         if(stat == TNG_CRITICAL)
1794         {
1795             fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n",
1796                     __FILE__, __LINE__);
1797             tng_block_destroy(&block);
1798             tng_data->input_file = temp;
1799             return(TNG_CRITICAL);
1800         }
1801         if(stat != TNG_SUCCESS || block->id != TNG_TRAJECTORY_FRAME_SET)
1802         {
1803             tng_data->input_file = temp;
1804             tng_block_destroy(&block);
1805             return(TNG_FAILURE);
1806         }
1807         stat = tng_length_of_current_frame_set_contents_get(tng_data, &frame_set_length);
1808         if(stat != TNG_SUCCESS)
1809         {
1810             tng_data->input_file = temp;
1811             tng_block_destroy(&block);
1812             return(stat);
1813         }
1814         stat = tng_frame_set_complete_migrate(tng_data, traj_start_pos,
1815                                               frame_set_length, tng_data->input_file_len);
1816         if(stat != TNG_SUCCESS)
1817         {
1818             tng_data->input_file = temp;
1819             tng_block_destroy(&block);
1820             return(stat);
1821         }
1822
1823         empty_space += frame_set_length;
1824     }
1825     fseek(tng_data->input_file, orig_file_pos, SEEK_SET);
1826     tng_block_destroy(&block);
1827
1828     return(TNG_SUCCESS);
1829 }
1830
1831 static tng_function_status tng_block_header_len_calculate
1832                 (const tng_trajectory_t tng_data,
1833                  tng_gen_block_t block,
1834                  int64_t *len)
1835 {
1836     int name_len;
1837     (void)tng_data;
1838
1839     /* If the string is unallocated allocate memory for just string
1840      * termination */
1841     if(!block->name)
1842     {
1843         block->name = malloc(1);
1844         if(!block->name)
1845         {
1846             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
1847                    __FILE__, __LINE__);
1848             return(TNG_CRITICAL);
1849         }
1850         block->name[0] = 0;
1851     }
1852
1853     name_len = tng_min_i((int)strlen(block->name) + 1, TNG_MAX_STR_LEN);
1854
1855     /* Calculate the size of the header to write */
1856     *len = sizeof(block->header_contents_size) +
1857                   sizeof(block->block_contents_size) +
1858                   sizeof(block->id) +
1859                   sizeof(block->block_version) +
1860                   TNG_MD5_HASH_LEN +
1861                   name_len;
1862
1863     return (TNG_SUCCESS);
1864 }
1865
1866 /** Write the header of a data block, regardless of its type
1867  * @param tng_data is a trajectory data container.
1868  * @param block is a general block container.
1869  * @param hash_mode is an option to decide whether to use the md5 hash or not.
1870  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
1871  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
1872  * error has occured.
1873  */
1874 static tng_function_status tng_block_header_write
1875                 (tng_trajectory_t tng_data,
1876                  tng_gen_block_t block,
1877                  const char hash_mode)
1878 {
1879     int name_len, offset = 0;
1880
1881     TNG_ASSERT(block != 0, "TNG library: Trying to write uninitialized block (NULL pointer).");
1882
1883     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
1884     {
1885         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
1886                __FILE__, __LINE__);
1887         return(TNG_CRITICAL);
1888     }
1889
1890     if(tng_block_header_len_calculate(tng_data, block, &block->header_contents_size) !=
1891         TNG_SUCCESS)
1892     {
1893         fprintf(stderr, "TNG library: Cannot calculate length of block header. %s: %d\n",
1894                 __FILE__, __LINE__);
1895         return(TNG_CRITICAL);
1896     }
1897
1898     if(hash_mode == TNG_USE_HASH)
1899     {
1900         tng_block_md5_hash_generate(block);
1901     }
1902
1903     if(block->header_contents)
1904     {
1905         free(block->header_contents);
1906     }
1907
1908     block->header_contents = malloc(block->header_contents_size);
1909     if(!block->header_contents)
1910     {
1911         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
1912                block->header_contents_size, __FILE__, __LINE__);
1913         return(TNG_CRITICAL);
1914     }
1915
1916     name_len = tng_min_i((int)strlen(block->name) + 1, TNG_MAX_STR_LEN);
1917
1918     /* First copy all data into the header_contents block and finally write
1919      * the whole block at once. */
1920     memcpy(block->header_contents, &block->header_contents_size,
1921            sizeof(block->header_contents_size));
1922     if(tng_data->output_endianness_swap_func_64)
1923     {
1924         if(tng_data->output_endianness_swap_func_64(tng_data,
1925                                       (int64_t *)block->header_contents+offset)
1926             != TNG_SUCCESS)
1927         {
1928             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1929                     __FILE__, __LINE__);
1930         }
1931     }
1932     offset += sizeof(block->header_contents_size);
1933
1934     memcpy(block->header_contents+offset, &block->block_contents_size,
1935            sizeof(block->block_contents_size));
1936     if(tng_data->output_endianness_swap_func_64)
1937     {
1938         if(tng_data->output_endianness_swap_func_64(tng_data,
1939                                       (int64_t *)block->header_contents+offset)
1940             != TNG_SUCCESS)
1941         {
1942             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1943                     __FILE__, __LINE__);
1944         }
1945     }
1946     offset += sizeof(block->block_contents_size);
1947
1948     memcpy(block->header_contents+offset, &block->id, sizeof(block->id));
1949     if(tng_data->output_endianness_swap_func_64)
1950     {
1951         if(tng_data->output_endianness_swap_func_64(tng_data,
1952                                       (int64_t *)block->header_contents+offset)
1953             != TNG_SUCCESS)
1954         {
1955             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1956                     __FILE__, __LINE__);
1957         }
1958     }
1959     offset += sizeof(block->id);
1960
1961     memcpy(block->header_contents+offset, block->md5_hash, TNG_MD5_HASH_LEN);
1962     offset += TNG_MD5_HASH_LEN;
1963
1964     strncpy(block->header_contents+offset, block->name, name_len);
1965     offset += name_len;
1966
1967     memcpy(block->header_contents+offset, &block->block_version,
1968            sizeof(block->block_version));
1969     if(tng_data->output_endianness_swap_func_64)
1970     {
1971         if(tng_data->output_endianness_swap_func_64(tng_data,
1972                                       (int64_t *)block->header_contents+offset)
1973             != TNG_SUCCESS)
1974         {
1975             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1976                     __FILE__, __LINE__);
1977         }
1978     }
1979
1980     if(fwrite(block->header_contents, block->header_contents_size,
1981        1, tng_data->output_file) != 1)
1982     {
1983         fprintf(stderr, "TNG library: Could not write all header data. %s: %d\n", __FILE__, __LINE__);
1984         return(TNG_CRITICAL);
1985     }
1986     return(TNG_SUCCESS);
1987 }
1988
1989 static tng_function_status tng_general_info_block_len_calculate
1990                 (tng_trajectory_t tng_data,
1991                  int64_t *len)
1992 {
1993     int first_program_name_len, first_user_name_len;
1994     int first_computer_name_len, first_pgp_signature_len;
1995     int last_program_name_len, last_user_name_len;
1996     int last_computer_name_len, last_pgp_signature_len;
1997     int forcefield_name_len;
1998
1999     /* If the strings are unallocated allocate memory for just string
2000      * termination */
2001     if(!tng_data->first_program_name)
2002     {
2003         tng_data->first_program_name = malloc(1);
2004         if(!tng_data->first_program_name)
2005         {
2006             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2007                    __FILE__, __LINE__);
2008             return(TNG_CRITICAL);
2009         }
2010         tng_data->first_program_name[0] = 0;
2011     }
2012     if(!tng_data->last_program_name)
2013     {
2014         tng_data->last_program_name = malloc(1);
2015         if(!tng_data->last_program_name)
2016         {
2017             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2018                    __FILE__, __LINE__);
2019             return(TNG_CRITICAL);
2020         }
2021         tng_data->last_program_name[0] = 0;
2022     }
2023     if(!tng_data->first_user_name)
2024     {
2025         tng_data->first_user_name = malloc(1);
2026         if(!tng_data->first_user_name)
2027         {
2028             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2029                    __FILE__, __LINE__);
2030             return(TNG_CRITICAL);
2031         }
2032         tng_data->first_user_name[0] = 0;
2033     }
2034     if(!tng_data->last_user_name)
2035     {
2036         tng_data->last_user_name = malloc(1);
2037         if(!tng_data->last_user_name)
2038         {
2039             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2040                    __FILE__, __LINE__);
2041             return(TNG_CRITICAL);
2042         }
2043         tng_data->last_user_name[0] = 0;
2044     }
2045     if(!tng_data->first_computer_name)
2046     {
2047         tng_data->first_computer_name = malloc(1);
2048         if(!tng_data->first_computer_name)
2049         {
2050             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2051                    __FILE__, __LINE__);
2052             return(TNG_CRITICAL);
2053         }
2054         tng_data->first_computer_name[0] = 0;
2055     }
2056     if(!tng_data->last_computer_name)
2057     {
2058         tng_data->last_computer_name = malloc(1);
2059         if(!tng_data->last_computer_name)
2060         {
2061             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2062                    __FILE__, __LINE__);
2063             return(TNG_CRITICAL);
2064         }
2065         tng_data->last_computer_name[0] = 0;
2066     }
2067     if(!tng_data->first_pgp_signature)
2068     {
2069         tng_data->first_pgp_signature = malloc(1);
2070         if(!tng_data->first_pgp_signature)
2071         {
2072             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2073                    __FILE__, __LINE__);
2074             return(TNG_CRITICAL);
2075         }
2076         tng_data->first_pgp_signature[0] = 0;
2077     }
2078     if(!tng_data->last_pgp_signature)
2079     {
2080         tng_data->last_pgp_signature = malloc(1);
2081         if(!tng_data->last_pgp_signature)
2082         {
2083             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2084                    __FILE__, __LINE__);
2085             return(TNG_CRITICAL);
2086         }
2087         tng_data->last_pgp_signature[0] = 0;
2088     }
2089     if(!tng_data->forcefield_name)
2090     {
2091         tng_data->forcefield_name = malloc(1);
2092         if(!tng_data->forcefield_name)
2093         {
2094             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2095                    __FILE__, __LINE__);
2096             return(TNG_CRITICAL);
2097         }
2098         tng_data->forcefield_name[0] = 0;
2099     }
2100
2101     first_program_name_len = tng_min_i((int)strlen(tng_data->first_program_name) + 1,
2102                            TNG_MAX_STR_LEN);
2103     last_program_name_len = tng_min_i((int)strlen(tng_data->last_program_name) + 1,
2104                            TNG_MAX_STR_LEN);
2105     first_user_name_len = tng_min_i((int)strlen(tng_data->first_user_name) + 1,
2106                         TNG_MAX_STR_LEN);
2107     last_user_name_len = tng_min_i((int)strlen(tng_data->last_user_name) + 1,
2108                         TNG_MAX_STR_LEN);
2109     first_computer_name_len = tng_min_i((int)strlen(tng_data->first_computer_name) + 1,
2110                             TNG_MAX_STR_LEN);
2111     last_computer_name_len = tng_min_i((int)strlen(tng_data->last_computer_name) + 1,
2112                             TNG_MAX_STR_LEN);
2113     first_pgp_signature_len = tng_min_i((int)strlen(tng_data->first_pgp_signature) + 1,
2114                             TNG_MAX_STR_LEN);
2115     last_pgp_signature_len = tng_min_i((int)strlen(tng_data->last_pgp_signature) + 1,
2116                             TNG_MAX_STR_LEN);
2117     forcefield_name_len = tng_min_i((int)strlen(tng_data->forcefield_name) + 1,
2118                               TNG_MAX_STR_LEN);
2119
2120     *len = sizeof(tng_data->time) +
2121                   sizeof(tng_data->var_num_atoms_flag) +
2122                   sizeof(tng_data->frame_set_n_frames) +
2123                   sizeof(tng_data->first_trajectory_frame_set_input_file_pos) +
2124                   sizeof(tng_data->last_trajectory_frame_set_input_file_pos) +
2125                   sizeof(tng_data->medium_stride_length) +
2126                   sizeof(tng_data->long_stride_length) +
2127                   sizeof(tng_data->distance_unit_exponential) +
2128                   first_program_name_len +
2129                   last_program_name_len +
2130                   first_user_name_len +
2131                   last_user_name_len +
2132                   first_computer_name_len +
2133                   last_computer_name_len +
2134                   first_pgp_signature_len +
2135                   last_pgp_signature_len +
2136                   forcefield_name_len;
2137
2138     return(TNG_SUCCESS);
2139 }
2140
2141 /** Read a general info block. This is the first block of a TNG file.
2142  *  Populate the fields in tng_data.
2143  * @param tng_data is a trajectory data container.
2144  * @param block is a general block container.
2145  * @param hash_mode is an option to decide whether to use the md5 hash or not.
2146  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
2147  * compared to the md5 hash of the read contents to ensure valid data.
2148  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
2149  * error has occured.
2150  */
2151 static tng_function_status tng_general_info_block_read
2152                 (tng_trajectory_t tng_data, tng_gen_block_t block,
2153                  const char hash_mode)
2154 {
2155     int len, offset = 0;
2156     tng_bool same_hash;
2157
2158     void *temp;
2159
2160     TNG_ASSERT(block != 0, "TNG library: Trying to read data to an uninitialized block (NULL pointer)");
2161
2162     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
2163     {
2164         return(TNG_CRITICAL);
2165     }
2166
2167     temp = realloc(block->block_contents, block->block_contents_size);
2168     if(!temp)
2169     {
2170         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
2171                block->block_contents_size, __FILE__, __LINE__);
2172         free(block->block_contents);
2173         block->block_contents = 0;
2174         return(TNG_CRITICAL);
2175     }
2176     block->block_contents = temp;
2177
2178     /* Read the whole block into block_contents to be able to write it to disk
2179      * even if it cannot be interpreted. */
2180     if(fread(block->block_contents, block->block_contents_size, 1,
2181              tng_data->input_file) == 0)
2182     {
2183         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
2184         return(TNG_CRITICAL);
2185     }
2186
2187     /* FIXME: Does not check if the size of the contents matches the expected
2188      * size or if the contents can be read. */
2189
2190     if(hash_mode == TNG_USE_HASH)
2191     {
2192         tng_md5_hash_match_verify(block, &same_hash);
2193         if(same_hash != TNG_TRUE)
2194         {
2195             fprintf(stderr, "TNG library: General info block contents corrupt. Hashes do not match. "
2196                 "%s: %d\n",
2197                 __FILE__, __LINE__);
2198     /*         return(TNG_FAILURE); */
2199         }
2200     }
2201
2202     len = tng_min_i((int)strlen(block->block_contents) + 1, TNG_MAX_STR_LEN);
2203     temp = realloc(tng_data->first_program_name, len);
2204     if(!temp)
2205     {
2206         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2207                __FILE__, __LINE__);
2208         free(tng_data->first_program_name);
2209         tng_data->first_program_name = 0;
2210         return(TNG_CRITICAL);
2211     }
2212     tng_data->first_program_name = temp;
2213     strncpy(tng_data->first_program_name, block->block_contents, len);
2214     offset += len;
2215
2216     len = tng_min_i((int)strlen(block->block_contents + offset) + 1, TNG_MAX_STR_LEN);
2217     temp = realloc(tng_data->last_program_name, len);
2218     if(!temp)
2219     {
2220         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2221                __FILE__, __LINE__);
2222         free(tng_data->last_program_name);
2223         tng_data->last_program_name = 0;
2224         return(TNG_CRITICAL);
2225     }
2226     tng_data->last_program_name = temp;
2227     strncpy(tng_data->last_program_name, block->block_contents + offset, len);
2228     offset += len;
2229
2230     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
2231     temp = realloc(tng_data->first_user_name, len);
2232     if(!temp)
2233     {
2234         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2235                __FILE__, __LINE__);
2236         free(tng_data->first_user_name);
2237         tng_data->first_user_name = 0;
2238         return(TNG_CRITICAL);
2239     }
2240     tng_data->first_user_name = temp;
2241     strncpy(tng_data->first_user_name, block->block_contents+offset, len);
2242     offset += len;
2243
2244     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
2245     temp = realloc(tng_data->last_user_name, len);
2246     if(!temp)
2247     {
2248         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2249                __FILE__, __LINE__);
2250         free(tng_data->last_user_name);
2251         tng_data->last_user_name = 0;
2252         return(TNG_CRITICAL);
2253     }
2254     tng_data->last_user_name = temp;
2255     strncpy(tng_data->last_user_name, block->block_contents+offset, len);
2256     offset += len;
2257
2258     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
2259     temp = realloc(tng_data->first_computer_name, len);
2260     if(!temp)
2261     {
2262         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2263                __FILE__, __LINE__);
2264         free(tng_data->first_computer_name);
2265         tng_data->first_computer_name = 0;
2266         return(TNG_CRITICAL);
2267     }
2268     tng_data->first_computer_name = temp;
2269     strncpy(tng_data->first_computer_name, block->block_contents+offset, len);
2270     offset += len;
2271
2272     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
2273     temp = realloc(tng_data->last_computer_name, len);
2274     if(!temp)
2275     {
2276         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2277                __FILE__, __LINE__);
2278         free(tng_data->last_computer_name);
2279         tng_data->last_computer_name = 0;
2280         return(TNG_CRITICAL);
2281     }
2282     tng_data->last_computer_name = temp;
2283     strncpy(tng_data->last_computer_name, block->block_contents+offset, len);
2284     offset += len;
2285
2286     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
2287     temp = realloc(tng_data->first_pgp_signature, len);
2288     if(!temp)
2289     {
2290         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2291                __FILE__, __LINE__);
2292         free(tng_data->first_pgp_signature);
2293         tng_data->first_pgp_signature = 0;
2294         return(TNG_CRITICAL);
2295     }
2296     tng_data->first_pgp_signature = temp;
2297     strncpy(tng_data->first_pgp_signature, block->block_contents+offset, len);
2298     offset += len;
2299
2300     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
2301     temp = realloc(tng_data->last_pgp_signature, len);
2302     if(!temp)
2303     {
2304         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2305                __FILE__, __LINE__);
2306         free(tng_data->last_pgp_signature);
2307         tng_data->last_pgp_signature = 0;
2308         return(TNG_CRITICAL);
2309     }
2310     tng_data->last_pgp_signature = temp;
2311     strncpy(tng_data->last_pgp_signature, block->block_contents+offset, len);
2312     offset += len;
2313
2314     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
2315     temp = realloc(tng_data->forcefield_name, len);
2316     if(!temp)
2317     {
2318         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2319                __FILE__, __LINE__);
2320         free(tng_data->forcefield_name);
2321         tng_data->forcefield_name = 0;
2322         return(TNG_CRITICAL);
2323     }
2324     tng_data->forcefield_name = temp;
2325     strncpy(tng_data->forcefield_name, block->block_contents+offset, len);
2326     offset += len;
2327
2328     memcpy(&tng_data->time, block->block_contents+offset,
2329            sizeof(tng_data->time));
2330     if(tng_data->input_endianness_swap_func_64)
2331     {
2332         if(tng_data->input_endianness_swap_func_64(tng_data,
2333                                                    &tng_data->time)
2334             != TNG_SUCCESS)
2335         {
2336             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2337                     __FILE__, __LINE__);
2338         }
2339     }
2340     offset += sizeof(tng_data->time);
2341
2342     memcpy(&tng_data->var_num_atoms_flag, block->block_contents+offset,
2343            sizeof(tng_data->var_num_atoms_flag));
2344     offset += sizeof(tng_data->var_num_atoms_flag);
2345
2346     memcpy(&tng_data->frame_set_n_frames, block->block_contents+offset,
2347            sizeof(tng_data->frame_set_n_frames));
2348     if(tng_data->input_endianness_swap_func_64)
2349     {
2350         if(tng_data->input_endianness_swap_func_64(tng_data,
2351                                                  &tng_data->frame_set_n_frames)
2352             != TNG_SUCCESS)
2353         {
2354             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2355                     __FILE__, __LINE__);
2356         }
2357     }
2358     offset += sizeof(tng_data->frame_set_n_frames);
2359
2360     memcpy(&tng_data->first_trajectory_frame_set_input_file_pos,
2361            block->block_contents+offset,
2362            sizeof(tng_data->first_trajectory_frame_set_input_file_pos));
2363     if(tng_data->input_endianness_swap_func_64)
2364     {
2365         if(tng_data->input_endianness_swap_func_64(tng_data,
2366                           &tng_data->first_trajectory_frame_set_input_file_pos)
2367             != TNG_SUCCESS)
2368         {
2369             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2370                     __FILE__, __LINE__);
2371         }
2372     }
2373     offset += sizeof(tng_data->first_trajectory_frame_set_input_file_pos);
2374
2375     tng_data->current_trajectory_frame_set.next_frame_set_file_pos =
2376     tng_data->first_trajectory_frame_set_input_file_pos;
2377
2378
2379     memcpy(&tng_data->last_trajectory_frame_set_input_file_pos,
2380            block->block_contents+offset,
2381            sizeof(tng_data->last_trajectory_frame_set_input_file_pos));
2382     if(tng_data->input_endianness_swap_func_64)
2383     {
2384         if(tng_data->input_endianness_swap_func_64(tng_data,
2385                           &tng_data->last_trajectory_frame_set_input_file_pos)
2386             != TNG_SUCCESS)
2387         {
2388             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2389                     __FILE__, __LINE__);
2390         }
2391     }
2392     offset += sizeof(tng_data->last_trajectory_frame_set_input_file_pos);
2393
2394     memcpy(&tng_data->medium_stride_length, block->block_contents+offset,
2395            sizeof(tng_data->medium_stride_length));
2396     if(tng_data->input_endianness_swap_func_64)
2397     {
2398         if(tng_data->input_endianness_swap_func_64(tng_data,
2399                                                &tng_data->medium_stride_length)
2400             != TNG_SUCCESS)
2401         {
2402             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2403                     __FILE__, __LINE__);
2404         }
2405     }
2406     offset += sizeof(tng_data->medium_stride_length);
2407
2408     memcpy(&tng_data->long_stride_length, block->block_contents+offset,
2409            sizeof(tng_data->long_stride_length));
2410     if(tng_data->input_endianness_swap_func_64)
2411     {
2412         if(tng_data->input_endianness_swap_func_64(tng_data,
2413                                                  &tng_data->long_stride_length)
2414             != TNG_SUCCESS)
2415         {
2416             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2417                     __FILE__, __LINE__);
2418         }
2419     }
2420     offset += sizeof(tng_data->long_stride_length);
2421
2422     if(block->block_version >= 3)
2423     {
2424         memcpy(&tng_data->distance_unit_exponential, block->block_contents+offset,
2425             sizeof(tng_data->distance_unit_exponential));
2426         if(tng_data->input_endianness_swap_func_64)
2427         {
2428             if(tng_data->input_endianness_swap_func_64(tng_data,
2429                                           &tng_data->distance_unit_exponential)
2430                 != TNG_SUCCESS)
2431             {
2432                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2433                         __FILE__, __LINE__);
2434             }
2435         }
2436     }
2437
2438     return(TNG_SUCCESS);
2439 }
2440
2441 /** Write a general info block. This is the first block of a TNG file.
2442  * @param tng_data is a trajectory data container.
2443  * @param hash_mode is an option to decide whether to use the md5 hash or not.
2444  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
2445  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
2446  * error has occured.
2447  */
2448 static tng_function_status tng_general_info_block_write
2449                 (tng_trajectory_t tng_data,
2450                  const char hash_mode)
2451 {
2452     int first_program_name_len, first_user_name_len;
2453     int first_computer_name_len, first_pgp_signature_len;
2454     int last_program_name_len, last_user_name_len;
2455     int last_computer_name_len, last_pgp_signature_len;
2456     int forcefield_name_len, name_len;
2457     int offset = 0;
2458     tng_gen_block_t block;
2459
2460     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
2461     {
2462         return(TNG_CRITICAL);
2463     }
2464
2465     fseek(tng_data->output_file, 0, SEEK_SET);
2466
2467     tng_block_init(&block);
2468
2469     name_len = (int)strlen("GENERAL INFO");
2470
2471     block->name = malloc(name_len + 1);
2472     if(!block->name)
2473     {
2474         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
2475                 name_len+1, __FILE__, __LINE__);
2476         tng_block_destroy(&block);
2477         return(TNG_CRITICAL);
2478     }
2479
2480     strcpy(block->name, "GENERAL INFO");
2481     block->id = TNG_GENERAL_INFO;
2482
2483     if(tng_general_info_block_len_calculate(tng_data, &block->block_contents_size) !=
2484         TNG_SUCCESS)
2485     {
2486         fprintf(stderr, "TNG library: Cannot calculate length of general info block. %s: %d\n",
2487                 __FILE__, __LINE__);
2488         tng_block_destroy(&block);
2489         return(TNG_CRITICAL);
2490     }
2491
2492     first_program_name_len = tng_min_i((int)strlen(tng_data->first_program_name) + 1,
2493                            TNG_MAX_STR_LEN);
2494     last_program_name_len = tng_min_i((int)strlen(tng_data->last_program_name) + 1,
2495                            TNG_MAX_STR_LEN);
2496     first_user_name_len = tng_min_i((int)strlen(tng_data->first_user_name) + 1,
2497                         TNG_MAX_STR_LEN);
2498     last_user_name_len = tng_min_i((int)strlen(tng_data->last_user_name) + 1,
2499                         TNG_MAX_STR_LEN);
2500     first_computer_name_len = tng_min_i((int)strlen(tng_data->first_computer_name) + 1,
2501                             TNG_MAX_STR_LEN);
2502     last_computer_name_len = tng_min_i((int)strlen(tng_data->last_computer_name) + 1,
2503                             TNG_MAX_STR_LEN);
2504     first_pgp_signature_len = tng_min_i((int)strlen(tng_data->first_pgp_signature) + 1,
2505                             TNG_MAX_STR_LEN);
2506     last_pgp_signature_len = tng_min_i((int)strlen(tng_data->last_pgp_signature) + 1,
2507                             TNG_MAX_STR_LEN);
2508     forcefield_name_len = tng_min_i((int)strlen(tng_data->forcefield_name) + 1,
2509                               TNG_MAX_STR_LEN);
2510
2511     if(block->block_contents)
2512     {
2513         free(block->block_contents);
2514     }
2515     block->block_contents = malloc(block->block_contents_size);
2516     if(!block->block_contents)
2517     {
2518         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
2519                block->block_contents_size, __FILE__, __LINE__);
2520         tng_block_destroy(&block);
2521         return(TNG_CRITICAL);
2522     }
2523
2524     strncpy(block->block_contents, tng_data->first_program_name, first_program_name_len);
2525     offset += first_program_name_len;
2526
2527     strncpy(block->block_contents+offset, tng_data->last_program_name, last_program_name_len);
2528     offset += last_program_name_len;
2529
2530     strncpy(block->block_contents+offset, tng_data->first_user_name, first_user_name_len);
2531     offset += first_user_name_len;
2532
2533     strncpy(block->block_contents+offset, tng_data->last_user_name, last_user_name_len);
2534     offset += last_user_name_len;
2535
2536     strncpy(block->block_contents+offset, tng_data->first_computer_name,
2537             first_computer_name_len);
2538     offset += first_computer_name_len;
2539
2540     strncpy(block->block_contents+offset, tng_data->last_computer_name,
2541             last_computer_name_len);
2542     offset += last_computer_name_len;
2543
2544     strncpy(block->block_contents+offset, tng_data->first_pgp_signature,
2545             first_pgp_signature_len);
2546     offset += first_pgp_signature_len;
2547
2548     strncpy(block->block_contents+offset, tng_data->last_pgp_signature,
2549             last_pgp_signature_len);
2550     offset += last_pgp_signature_len;
2551
2552     strncpy(block->block_contents+offset, tng_data->forcefield_name,
2553             forcefield_name_len);
2554     offset += forcefield_name_len;
2555
2556     memcpy(block->block_contents+offset, &tng_data->time,
2557            sizeof(tng_data->time));
2558     if(tng_data->output_endianness_swap_func_64)
2559     {
2560         if(tng_data->output_endianness_swap_func_64(tng_data,
2561                                       (int64_t *)block->header_contents+offset)
2562             != TNG_SUCCESS)
2563         {
2564             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2565                     __FILE__, __LINE__);
2566         }
2567     }
2568     offset += sizeof(tng_data->time);
2569
2570     memcpy(block->block_contents+offset, &tng_data->var_num_atoms_flag,
2571            sizeof(tng_data->var_num_atoms_flag));
2572     offset += sizeof(tng_data->var_num_atoms_flag);
2573
2574     memcpy(block->block_contents+offset, &tng_data->frame_set_n_frames,
2575            sizeof(tng_data->frame_set_n_frames));
2576     if(tng_data->output_endianness_swap_func_64)
2577     {
2578         if(tng_data->output_endianness_swap_func_64(tng_data,
2579                                       (int64_t *)block->header_contents+offset)
2580             != TNG_SUCCESS)
2581         {
2582             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2583                     __FILE__, __LINE__);
2584         }
2585     }
2586     offset += sizeof(tng_data->frame_set_n_frames);
2587
2588     memcpy(block->block_contents+offset,
2589            &tng_data->first_trajectory_frame_set_output_file_pos,
2590            sizeof(tng_data->first_trajectory_frame_set_output_file_pos));
2591     if(tng_data->output_endianness_swap_func_64)
2592     {
2593         if(tng_data->output_endianness_swap_func_64(tng_data,
2594                                       (int64_t *)block->header_contents+offset)
2595             != TNG_SUCCESS)
2596         {
2597             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2598                     __FILE__, __LINE__);
2599         }
2600     }
2601     offset += sizeof(tng_data->first_trajectory_frame_set_output_file_pos);
2602
2603     memcpy(block->block_contents+offset,
2604            &tng_data->last_trajectory_frame_set_output_file_pos,
2605            sizeof(tng_data->last_trajectory_frame_set_output_file_pos));
2606     if(tng_data->output_endianness_swap_func_64)
2607     {
2608         if(tng_data->output_endianness_swap_func_64(tng_data,
2609                                       (int64_t *)block->header_contents+offset)
2610             != TNG_SUCCESS)
2611         {
2612             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2613                     __FILE__, __LINE__);
2614         }
2615     }
2616     offset += sizeof(tng_data->last_trajectory_frame_set_output_file_pos);
2617
2618     memcpy(block->block_contents+offset, &tng_data->medium_stride_length,
2619            sizeof(tng_data->medium_stride_length));
2620     if(tng_data->output_endianness_swap_func_64)
2621     {
2622         if(tng_data->output_endianness_swap_func_64(tng_data,
2623                                       (int64_t *)block->header_contents+offset)
2624             != TNG_SUCCESS)
2625         {
2626             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2627                     __FILE__, __LINE__);
2628         }
2629     }
2630     offset += sizeof(tng_data->medium_stride_length);
2631
2632     memcpy(block->block_contents+offset, &tng_data->long_stride_length,
2633            sizeof(tng_data->long_stride_length));
2634     if(tng_data->output_endianness_swap_func_64)
2635     {
2636         if(tng_data->output_endianness_swap_func_64(tng_data,
2637                                       (int64_t *)block->header_contents+offset)
2638             != TNG_SUCCESS)
2639         {
2640             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2641                     __FILE__, __LINE__);
2642         }
2643     }
2644     offset += sizeof(tng_data->long_stride_length);
2645
2646     memcpy(block->block_contents+offset, &tng_data->distance_unit_exponential,
2647            sizeof(tng_data->distance_unit_exponential));
2648     if(tng_data->output_endianness_swap_func_64)
2649     {
2650         if(tng_data->output_endianness_swap_func_64(tng_data,
2651                                       (int64_t *)block->header_contents+offset)
2652             != TNG_SUCCESS)
2653         {
2654             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2655                     __FILE__, __LINE__);
2656         }
2657     }
2658
2659     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
2660     {
2661         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
2662                tng_data->output_file_path, __FILE__, __LINE__);
2663         tng_block_destroy(&block);
2664         return(TNG_CRITICAL);
2665     }
2666
2667     if(fwrite(block->block_contents, block->block_contents_size, 1,
2668         tng_data->output_file) != 1)
2669     {
2670         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__, __LINE__);
2671         tng_block_destroy(&block);
2672         return(TNG_CRITICAL);
2673     }
2674
2675     tng_block_destroy(&block);
2676
2677     return(TNG_SUCCESS);
2678 }
2679
2680 /** Read the chain data of a molecules block.
2681  * @param tng_data is a trajectory data container.
2682  * @param block is a general block container.
2683  * @param chain is the chain data container.
2684  * @param offset is the offset of the block input and is updated when reading.
2685  * @return TNG_SUCCESS(0) is successful.
2686  */
2687 static tng_function_status tng_chain_data_read(tng_trajectory_t tng_data,
2688                                                tng_gen_block_t block,
2689                                                tng_chain_t chain,
2690                                                int *offset)
2691 {
2692     int len;
2693
2694     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
2695
2696     memcpy(&chain->id, block->block_contents+*offset,
2697             sizeof(chain->id));
2698     if(tng_data->input_endianness_swap_func_64)
2699     {
2700         if(tng_data->input_endianness_swap_func_64(tng_data,
2701                                                    &chain->id)
2702             != TNG_SUCCESS)
2703         {
2704             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2705                     __FILE__, __LINE__);
2706         }
2707     }
2708     *offset += sizeof(chain->id);
2709
2710     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
2711             TNG_MAX_STR_LEN);
2712     chain->name = malloc(len);
2713     strncpy(chain->name,
2714             block->block_contents+*offset, len);
2715     *offset += len;
2716
2717     memcpy(&chain->n_residues, block->block_contents+*offset,
2718         sizeof(chain->n_residues));
2719     if(tng_data->input_endianness_swap_func_64)
2720     {
2721         if(tng_data->input_endianness_swap_func_64(tng_data,
2722                                                    &chain->n_residues)
2723             != TNG_SUCCESS)
2724         {
2725             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2726                     __FILE__, __LINE__);
2727         }
2728     }
2729     *offset += sizeof(chain->n_residues);
2730
2731     return(TNG_SUCCESS);
2732 }
2733
2734 /** Write the chain data of a molecules block.
2735  * @param tng_data is a trajectory data container.
2736  * @param block is a general block container.
2737  * @param chain is the chain data container.
2738  * @param offset is the offset of the block output and is updated when writing.
2739  * @return TNG_SUCCESS(0) is successful.
2740  */
2741 static tng_function_status tng_chain_data_write(tng_trajectory_t tng_data,
2742                                                 tng_gen_block_t block,
2743                                                 tng_chain_t chain,
2744                                                 int *offset)
2745 {
2746     int len;
2747
2748     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
2749
2750     memcpy(block->block_contents+*offset, &chain->id, sizeof(chain->id));
2751     if(tng_data->output_endianness_swap_func_64)
2752     {
2753         if(tng_data->output_endianness_swap_func_64(tng_data,
2754                                     (int64_t *)block->header_contents+*offset)
2755             != TNG_SUCCESS)
2756         {
2757             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2758                     __FILE__, __LINE__);
2759         }
2760     }
2761     *offset += sizeof(chain->id);
2762
2763     len = tng_min_i((int)strlen(chain->name) + 1, TNG_MAX_STR_LEN);
2764     strncpy(block->block_contents + *offset, chain->name, len);
2765     *offset += len;
2766
2767     memcpy(block->block_contents+*offset, &chain->n_residues,
2768         sizeof(chain->n_residues));
2769     if(tng_data->output_endianness_swap_func_64)
2770     {
2771         if(tng_data->output_endianness_swap_func_64(tng_data,
2772                                     (int64_t *)block->header_contents+*offset)
2773             != TNG_SUCCESS)
2774         {
2775             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2776                     __FILE__, __LINE__);
2777         }
2778     }
2779     *offset += sizeof(chain->n_residues);
2780
2781     return(TNG_SUCCESS);
2782 }
2783
2784 /** Read the residue data of a molecules block.
2785  * @param tng_data is a trajectory data container.
2786  * @param block is a general block container.
2787  * @param residue is the residue data container.
2788  * @param offset is the offset of the block input and is updated when reading.
2789  * @return TNG_SUCCESS(0) is successful.
2790  */
2791 static tng_function_status tng_residue_data_read(tng_trajectory_t tng_data,
2792                                                  tng_gen_block_t block,
2793                                                  tng_residue_t residue,
2794                                                  int *offset)
2795 {
2796     int len;
2797
2798     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
2799
2800     memcpy(&residue->id, block->block_contents+*offset,
2801         sizeof(residue->id));
2802     if(tng_data->input_endianness_swap_func_64)
2803     {
2804         if(tng_data->input_endianness_swap_func_64(tng_data,
2805                                                    &residue->id)
2806             != TNG_SUCCESS)
2807         {
2808             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2809                     __FILE__, __LINE__);
2810         }
2811     }
2812     *offset += sizeof(residue->id);
2813
2814     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
2815             TNG_MAX_STR_LEN);
2816     residue->name = malloc(len);
2817     strncpy(residue->name,
2818             block->block_contents+*offset, len);
2819     *offset += len;
2820
2821     memcpy(&residue->n_atoms, block->block_contents+*offset,
2822             sizeof(residue->n_atoms));
2823     if(tng_data->input_endianness_swap_func_64)
2824     {
2825         if(tng_data->input_endianness_swap_func_64(tng_data,
2826                                                    &residue->n_atoms)
2827             != TNG_SUCCESS)
2828         {
2829             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2830                     __FILE__, __LINE__);
2831         }
2832     }
2833     *offset += sizeof(residue->n_atoms);
2834
2835     return(TNG_SUCCESS);
2836 }
2837
2838 /** Write the residue data of a molecules block.
2839  * @param tng_data is a trajectory data container.
2840  * @param block is a general block container.
2841  * @param residue is the residue data container.
2842  * @param offset is the offset of the block output and is updated when writing.
2843  * @return TNG_SUCCESS(0) is successful.
2844  */
2845 static tng_function_status tng_residue_data_write(tng_trajectory_t tng_data,
2846                                                   tng_gen_block_t block,
2847                                                   tng_residue_t residue,
2848                                                   int *offset)
2849 {
2850     int len;
2851
2852     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
2853
2854     memcpy(block->block_contents+*offset, &residue->id, sizeof(residue->id));
2855     if(tng_data->output_endianness_swap_func_64)
2856     {
2857         if(tng_data->output_endianness_swap_func_64(tng_data,
2858                                     (int64_t *)block->header_contents+*offset)
2859             != TNG_SUCCESS)
2860         {
2861             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2862                     __FILE__, __LINE__);
2863         }
2864     }
2865     *offset += sizeof(residue->id);
2866
2867     len = tng_min_i((int)strlen(residue->name) + 1, TNG_MAX_STR_LEN);
2868     strncpy(block->block_contents + *offset, residue->name, len);
2869     *offset += len;
2870
2871     memcpy(block->block_contents+*offset, &residue->n_atoms,
2872         sizeof(residue->n_atoms));
2873     if(tng_data->output_endianness_swap_func_64)
2874     {
2875         if(tng_data->output_endianness_swap_func_64(tng_data,
2876                                     (int64_t *)block->header_contents+*offset)
2877             != TNG_SUCCESS)
2878         {
2879             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2880                     __FILE__, __LINE__);
2881         }
2882     }
2883     *offset += sizeof(residue->n_atoms);
2884
2885     return(TNG_SUCCESS);
2886 }
2887
2888 /** Read the atom data of a molecules block.
2889  * @param tng_data is a trajectory data container.
2890  * @param block is a general block container.
2891  * @param atom is the atom data container.
2892  * @param offset is the offset of the block input and is updated when reading.
2893  * @return TNG_SUCCESS(0) is successful.
2894  */
2895 static tng_function_status tng_atom_data_read(tng_trajectory_t tng_data,
2896                                               tng_gen_block_t block,
2897                                               tng_atom_t atom,
2898                                               int *offset)
2899 {
2900     int len;
2901
2902     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
2903
2904     memcpy(&atom->id, block->block_contents+*offset,
2905         sizeof(atom->id));
2906     if(tng_data->input_endianness_swap_func_64)
2907     {
2908         if(tng_data->input_endianness_swap_func_64(tng_data,
2909                                                     &atom->id)
2910             != TNG_SUCCESS)
2911         {
2912             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2913                     __FILE__, __LINE__);
2914         }
2915     }
2916     *offset += sizeof(atom->id);
2917
2918     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
2919             TNG_MAX_STR_LEN);
2920     atom->name = malloc(len);
2921     strncpy(atom->name,
2922             block->block_contents+*offset, len);
2923     *offset += len;
2924
2925     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
2926             TNG_MAX_STR_LEN);
2927     atom->atom_type = malloc(len);
2928     strncpy(atom->atom_type,
2929             block->block_contents+*offset, len);
2930     *offset += len;
2931
2932     return(TNG_SUCCESS);
2933 }
2934
2935 /** Write the atom data of a molecules block.
2936  * @param tng_data is a trajectory data container.
2937  * @param block is a general block container.
2938  * @param atom is the atom data container.
2939  * @param offset is the offset of the block output and is updated when writing.
2940  * @return TNG_SUCCESS(0) is successful.
2941  */
2942 static tng_function_status tng_atom_data_write(tng_trajectory_t tng_data,
2943                                                tng_gen_block_t block,
2944                                                tng_atom_t atom,
2945                                                int *offset)
2946 {
2947     int len;
2948
2949     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
2950
2951     memcpy(block->block_contents+*offset, &atom->id,
2952             sizeof(atom->id));
2953     if(tng_data->output_endianness_swap_func_64)
2954     {
2955         if(tng_data->output_endianness_swap_func_64(tng_data,
2956                                     (int64_t *)block->header_contents+*offset)
2957             != TNG_SUCCESS)
2958         {
2959             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2960                     __FILE__, __LINE__);
2961         }
2962     }
2963     *offset += sizeof(atom->id);
2964
2965     len = tng_min_i((int)strlen(atom->name) + 1, TNG_MAX_STR_LEN);
2966     strncpy(block->block_contents + *offset, atom->name, len);
2967     *offset += len;
2968
2969     len = tng_min_i((int)strlen(atom->atom_type) + 1, TNG_MAX_STR_LEN);
2970     strncpy(block->block_contents + *offset, atom->atom_type, len);
2971     *offset += len;
2972
2973     return(TNG_SUCCESS);
2974 }
2975
2976 static tng_function_status tng_molecules_block_len_calculate
2977                 (const tng_trajectory_t tng_data,
2978                  int64_t *len)
2979 {
2980     int64_t i, j;
2981     tng_molecule_t molecule;
2982     tng_chain_t chain;
2983     tng_residue_t residue;
2984     tng_atom_t atom;
2985     tng_bond_t bond;
2986
2987     *len = 0;
2988
2989     for(i = 0; i < tng_data->n_molecules; i++)
2990     {
2991         molecule = &tng_data->molecules[i];
2992         if(!molecule->name)
2993         {
2994             molecule->name = malloc(1);
2995             if(!molecule->name)
2996             {
2997                 fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2998                        __FILE__, __LINE__);
2999                 return(TNG_CRITICAL);
3000             }
3001             molecule->name[0] = 0;
3002         }
3003         *len += tng_min_i((int)strlen(molecule->name) + 1, TNG_MAX_STR_LEN);
3004
3005         chain = molecule->chains;
3006         for(j = 0; j < molecule->n_chains; j++)
3007         {
3008             *len += sizeof(chain->id);
3009
3010             if(!chain->name)
3011             {
3012                 chain->name = malloc(1);
3013                 if(!chain->name)
3014                 {
3015                     fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
3016                            __FILE__, __LINE__);
3017                     return(TNG_CRITICAL);
3018                 }
3019                 chain->name[0] = 0;
3020             }
3021             *len += tng_min_i((int)strlen(chain->name) + 1, TNG_MAX_STR_LEN);
3022
3023             *len += sizeof(chain->n_residues);
3024
3025             chain++;
3026         }
3027
3028         residue = molecule->residues;
3029         for(j = 0; j < molecule->n_residues; j++)
3030         {
3031             *len += sizeof(residue->id);
3032
3033             if(!residue->name)
3034             {
3035                 residue->name = malloc(1);
3036                 if(!residue->name)
3037                 {
3038                     fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
3039                            __FILE__, __LINE__);
3040                     return(TNG_CRITICAL);
3041                 }
3042                 residue->name[0] = 0;
3043             }
3044             *len += tng_min_i((int)strlen(residue->name) + 1, TNG_MAX_STR_LEN);
3045
3046             *len += sizeof(residue->n_atoms);
3047
3048             residue++;
3049         }
3050
3051         atom = molecule->atoms;
3052         for(j = 0; j < molecule->n_atoms; j++)
3053         {
3054             *len += sizeof(atom->id);
3055             if(!atom->name)
3056             {
3057                 atom->name = malloc(1);
3058                 if(!atom->name)
3059                 {
3060                     fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
3061                            __FILE__, __LINE__);
3062                     return(TNG_CRITICAL);
3063                 }
3064                 atom->name[0] = 0;
3065             }
3066             *len += tng_min_i((int)strlen(atom->name) + 1, TNG_MAX_STR_LEN);
3067
3068             if(!atom->atom_type)
3069             {
3070                 atom->atom_type = malloc(1);
3071                 if(!atom->atom_type)
3072                 {
3073                     fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
3074                            __FILE__, __LINE__);
3075                     return(TNG_CRITICAL);
3076                 }
3077                 atom->atom_type[0] = 0;
3078             }
3079             *len += tng_min_i((int)strlen(atom->atom_type) + 1, TNG_MAX_STR_LEN);
3080
3081             atom++;
3082         }
3083
3084         for(j = 0; j < molecule->n_bonds; j++)
3085         {
3086             *len += sizeof(bond->from_atom_id) + sizeof(bond->to_atom_id);
3087         }
3088     }
3089     *len += sizeof(tng_data->n_molecules) +
3090             (sizeof(molecule->id) +
3091             sizeof(molecule->quaternary_str) +
3092             sizeof(molecule->n_chains) +
3093             sizeof(molecule->n_residues) +
3094             sizeof(molecule->n_atoms) +
3095             sizeof(molecule->n_bonds)) *
3096             tng_data->n_molecules;
3097
3098     if(!tng_data->var_num_atoms_flag)
3099     {
3100         *len += tng_data->n_molecules * sizeof(int64_t);
3101     }
3102
3103     return(TNG_SUCCESS);
3104 }
3105
3106 /** Read a molecules block. Contains chain, residue and atom data
3107  * @param tng_data is a trajectory data container.
3108  * @param block is a general block container.
3109  * @param hash_mode is an option to decide whether to use the md5 hash or not.
3110  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
3111  * compared to the md5 hash of the read contents to ensure valid data.
3112  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
3113  * error has occured.
3114  */
3115 static tng_function_status tng_molecules_block_read
3116                 (tng_trajectory_t tng_data,
3117                  tng_gen_block_t block,
3118                  const char hash_mode)
3119 {
3120     int64_t i, j, k, l;
3121     int len, offset = 0;
3122     tng_molecule_t molecule;
3123     tng_chain_t chain;
3124     tng_residue_t residue;
3125     tng_atom_t atom;
3126     tng_bond_t bond;
3127     tng_bool same_hash;
3128
3129     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
3130     {
3131         return(TNG_CRITICAL);
3132     }
3133
3134     if(block->block_contents)
3135     {
3136         free(block->block_contents);
3137     }
3138
3139     block->block_contents = malloc(block->block_contents_size);
3140     if(!block->block_contents)
3141     {
3142         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3143                block->block_contents_size, __FILE__, __LINE__);
3144         return(TNG_CRITICAL);
3145     }
3146
3147     /* Read the whole block into block_contents to be able to write it to disk
3148      * even if it cannot be interpreted. */
3149     if(fread(block->block_contents, block->block_contents_size, 1,
3150              tng_data->input_file) == 0)
3151     {
3152         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
3153     }
3154
3155     /* FIXME: Does not check if the size of the contents matches the expected
3156      * size or if the contents can be read. */
3157
3158     if(hash_mode == TNG_USE_HASH)
3159     {
3160         tng_md5_hash_match_verify(block, &same_hash);
3161         if(same_hash != TNG_TRUE)
3162         {
3163             fprintf(stderr, "TNG library: Molecules block contents corrupt. Hashes do not match. "
3164                 "%s: %d\n",
3165                 __FILE__, __LINE__);
3166         }
3167     }
3168
3169     if(tng_data->molecules)
3170     {
3171         for(i=0; i<tng_data->n_molecules; i++)
3172         {
3173             tng_molecule_destroy(tng_data, &tng_data->molecules[i]);
3174         }
3175         free(tng_data->molecules);
3176         tng_data->molecules = 0;
3177         tng_data->n_molecules = 0;
3178     }
3179
3180     memcpy(&tng_data->n_molecules, block->block_contents,
3181            sizeof(tng_data->n_molecules));
3182     if(tng_data->input_endianness_swap_func_64)
3183     {
3184         if(tng_data->input_endianness_swap_func_64(tng_data,
3185                                                    &tng_data->n_molecules)
3186             != TNG_SUCCESS)
3187         {
3188             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3189                     __FILE__, __LINE__);
3190         }
3191     }
3192     offset += sizeof(tng_data->n_molecules);
3193
3194     if(tng_data->molecules)
3195     {
3196         free(tng_data->molecules);
3197     }
3198
3199     tng_data->n_particles = 0;
3200
3201     tng_data->molecules = malloc(tng_data->n_molecules *
3202                           sizeof(struct tng_molecule));
3203     if(!tng_data->molecules)
3204     {
3205         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3206                tng_data->n_molecules * sizeof(struct tng_molecule),
3207                __FILE__, __LINE__);
3208         return(TNG_CRITICAL);
3209     }
3210
3211     if(!tng_data->var_num_atoms_flag)
3212     {
3213         if(tng_data->molecule_cnt_list)
3214         {
3215             free(tng_data->molecule_cnt_list);
3216         }
3217         tng_data->molecule_cnt_list = malloc(sizeof(int64_t) *
3218                                       tng_data->n_molecules);
3219         if(!tng_data->molecule_cnt_list)
3220         {
3221             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3222                    tng_data->n_molecules * sizeof(struct tng_molecule),
3223                    __FILE__, __LINE__);
3224             return(TNG_CRITICAL);
3225         }
3226     }
3227
3228     /* Read each molecule from file */
3229     for(i=0; i < tng_data->n_molecules; i++)
3230     {
3231         molecule = &tng_data->molecules[i];
3232
3233         memcpy(&molecule->id, block->block_contents+offset,
3234                sizeof(molecule->id));
3235         if(tng_data->input_endianness_swap_func_64)
3236         {
3237             if(tng_data->input_endianness_swap_func_64(tng_data,
3238                                                        &molecule->id)
3239                 != TNG_SUCCESS)
3240             {
3241                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3242                         __FILE__, __LINE__);
3243             }
3244         }
3245         offset += sizeof(molecule->id);
3246
3247 /*         fprintf(stderr, "TNG library: Read id: %"PRId64" offset: %d\n", molecule->id, offset);*/
3248         len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
3249         molecule->name = malloc(len);
3250         strncpy(molecule->name, block->block_contents+offset, len);
3251         offset += len;
3252
3253         memcpy(&molecule->quaternary_str, block->block_contents+offset,
3254                sizeof(molecule->quaternary_str));
3255         if(tng_data->input_endianness_swap_func_64)
3256         {
3257             if(tng_data->input_endianness_swap_func_64(tng_data,
3258                                                      &molecule->quaternary_str)
3259                 != TNG_SUCCESS)
3260             {
3261                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3262                         __FILE__, __LINE__);
3263             }
3264         }
3265         offset += sizeof(molecule->quaternary_str);
3266
3267         if(!tng_data->var_num_atoms_flag)
3268         {
3269             memcpy(&tng_data->molecule_cnt_list[i],
3270                    block->block_contents+offset,
3271                    sizeof(int64_t));
3272             if(tng_data->input_endianness_swap_func_64)
3273             {
3274                 if(tng_data->input_endianness_swap_func_64(tng_data,
3275                                                &tng_data->molecule_cnt_list[i])
3276                     != TNG_SUCCESS)
3277                 {
3278                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3279                             __FILE__, __LINE__);
3280                 }
3281             }
3282             offset += sizeof(int64_t);
3283         }
3284
3285
3286         memcpy(&molecule->n_chains, block->block_contents+offset,
3287                sizeof(molecule->n_chains));
3288         if(tng_data->input_endianness_swap_func_64)
3289         {
3290             if(tng_data->input_endianness_swap_func_64(tng_data,
3291                                                        &molecule->n_chains)
3292                 != TNG_SUCCESS)
3293             {
3294                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3295                         __FILE__, __LINE__);
3296             }
3297         }
3298         offset += sizeof(molecule->n_chains);
3299
3300         memcpy(&molecule->n_residues, block->block_contents+offset,
3301                sizeof(molecule->n_residues));
3302         if(tng_data->input_endianness_swap_func_64)
3303         {
3304             if(tng_data->input_endianness_swap_func_64(tng_data,
3305                                                        &molecule->n_residues)
3306                 != TNG_SUCCESS)
3307             {
3308                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3309                         __FILE__, __LINE__);
3310             }
3311         }
3312         offset += sizeof(molecule->n_residues);
3313
3314         memcpy(&molecule->n_atoms, block->block_contents+offset,
3315                sizeof(molecule->n_atoms));
3316         if(tng_data->input_endianness_swap_func_64)
3317         {
3318             if(tng_data->input_endianness_swap_func_64(tng_data,
3319                                                        &molecule->n_atoms)
3320                 != TNG_SUCCESS)
3321             {
3322                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3323                         __FILE__, __LINE__);
3324             }
3325         }
3326         offset += sizeof(molecule->n_atoms);
3327
3328         tng_data->n_particles += molecule->n_atoms *
3329                                  tng_data->molecule_cnt_list[i];
3330
3331         if(molecule->n_chains > 0)
3332         {
3333             molecule->chains = malloc(molecule->n_chains *
3334                                     sizeof(struct tng_chain));
3335             if(!molecule->chains)
3336             {
3337                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3338                     molecule->n_chains * sizeof(struct tng_chain),
3339                     __FILE__, __LINE__);
3340                 return(TNG_CRITICAL);
3341             }
3342
3343             chain = molecule->chains;
3344         }
3345         else
3346         {
3347             chain = 0;
3348         }
3349
3350         if(molecule->n_residues > 0)
3351         {
3352             molecule->residues = malloc(molecule->n_residues *
3353                                 sizeof(struct tng_residue));
3354             if(!molecule->residues)
3355             {
3356                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3357                     molecule->n_residues * sizeof(struct tng_residue),
3358                     __FILE__, __LINE__);
3359                 if(molecule->chains)
3360                 {
3361                     free(molecule->chains);
3362                     molecule->chains = 0;
3363                 }
3364                 return(TNG_CRITICAL);
3365             }
3366
3367             residue = molecule->residues;
3368         }
3369         else
3370         {
3371             residue = 0;
3372         }
3373
3374         molecule->atoms = malloc(molecule->n_atoms *
3375                                  sizeof(struct tng_atom));
3376         if(!molecule->atoms)
3377         {
3378             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3379                    molecule->n_atoms * sizeof(struct tng_atom),
3380                    __FILE__, __LINE__);
3381             if(molecule->chains)
3382             {
3383                 free(molecule->chains);
3384                 molecule->chains = 0;
3385             }
3386             if(molecule->residues)
3387             {
3388                 free(molecule->residues);
3389                 molecule->residues = 0;
3390             }
3391             return(TNG_CRITICAL);
3392         }
3393
3394         atom = molecule->atoms;
3395
3396         if(molecule->n_chains > 0)
3397         {
3398             /* Read the chains of the molecule */
3399             for(j=0; j<molecule->n_chains; j++)
3400             {
3401                 chain->molecule = molecule;
3402
3403                 tng_chain_data_read(tng_data, block, chain, &offset);
3404
3405                 chain->residues = molecule->residues;
3406                 residue = chain->residues;
3407
3408                 /* Read the residues of the chain */
3409                 for(k=0; k<chain->n_residues; k++)
3410                 {
3411                     residue->chain = chain;
3412
3413                     tng_residue_data_read(tng_data, block, residue, &offset);
3414
3415                     residue->atoms_offset = atom - molecule->atoms;
3416                     /* Read the atoms of the residue */
3417                     for(l=0; l<residue->n_atoms; l++)
3418                     {
3419                         atom->residue = residue;
3420
3421                         tng_atom_data_read(tng_data, block, atom, &offset);
3422
3423                         atom++;
3424                     }
3425                     residue++;
3426                 }
3427                 chain++;
3428             }
3429         }
3430         else
3431         {
3432             if(molecule->n_residues > 0)
3433             {
3434                 for(k=0; k<molecule->n_residues; k++)
3435                 {
3436                     residue->chain = 0;
3437
3438                     tng_residue_data_read(tng_data, block, residue, &offset);
3439
3440                     residue->atoms_offset = atom - molecule->atoms;
3441                     /* Read the atoms of the residue */
3442                     for(l=0; l<residue->n_atoms; l++)
3443                     {
3444                         atom->residue = residue;
3445
3446                         tng_atom_data_read(tng_data, block, atom, &offset);
3447
3448                         atom++;
3449                     }
3450                     residue++;
3451                 }
3452             }
3453             else
3454             {
3455                 for(l=0; l<molecule->n_atoms; l++)
3456                 {
3457                     atom->residue = 0;
3458
3459                     tng_atom_data_read(tng_data, block, atom, &offset);
3460
3461                     atom++;
3462                 }
3463             }
3464         }
3465
3466         memcpy(&molecule->n_bonds, block->block_contents+offset,
3467                sizeof(molecule->n_bonds));
3468         if(tng_data->input_endianness_swap_func_64)
3469         {
3470             if(tng_data->input_endianness_swap_func_64(tng_data,
3471                                                        &molecule->n_bonds)
3472                 != TNG_SUCCESS)
3473             {
3474                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3475                         __FILE__, __LINE__);
3476             }
3477         }
3478         offset += sizeof(molecule->n_bonds);
3479
3480         if(molecule->n_bonds > 0)
3481         {
3482             tng_data->molecules[i].bonds = malloc(molecule->n_bonds *
3483                                            sizeof(struct tng_bond));
3484             if(!molecule->bonds)
3485             {
3486                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3487                        molecule->n_bonds * sizeof(struct tng_bond),
3488                        __FILE__, __LINE__);
3489                 if(molecule->chains)
3490                 {
3491                     free(molecule->chains);
3492                     molecule->chains = 0;
3493                 }
3494                 if(molecule->residues)
3495                 {
3496                     free(molecule->residues);
3497                     molecule->residues = 0;
3498                 }
3499                 if(molecule->atoms)
3500                 {
3501                     free(molecule->atoms);
3502                     molecule->atoms = 0;
3503                 }
3504                 return(TNG_CRITICAL);
3505             }
3506
3507             bond = molecule->bonds;
3508
3509             for(j=0; j<molecule->n_bonds; j++)
3510             {
3511                 memcpy(&bond->from_atom_id, block->block_contents+offset,
3512                     sizeof(bond->from_atom_id));
3513                 if(tng_data->input_endianness_swap_func_64)
3514                 {
3515                     if(tng_data->input_endianness_swap_func_64(tng_data,
3516                                                                &bond->from_atom_id)
3517                         != TNG_SUCCESS)
3518                     {
3519                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3520                                 __FILE__, __LINE__);
3521                     }
3522                 }
3523                 offset += sizeof(bond->from_atom_id);
3524
3525                 memcpy(&bond->to_atom_id, block->block_contents+offset,
3526                     sizeof(bond->to_atom_id));
3527                 if(tng_data->input_endianness_swap_func_64)
3528                 {
3529                     if(tng_data->input_endianness_swap_func_64(tng_data,
3530                                                                &bond->to_atom_id)
3531                         != TNG_SUCCESS)
3532                     {
3533                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3534                                 __FILE__, __LINE__);
3535                     }
3536                 }
3537                 offset += sizeof(bond->to_atom_id);
3538
3539                 bond++;
3540             }
3541         }
3542         else
3543         {
3544             molecule->bonds = 0;
3545         }
3546     }
3547
3548     return(TNG_SUCCESS);
3549 }
3550
3551 /** Write a molecules block.
3552  * @param tng_data is a trajectory data container.
3553  * @param hash_mode is an option to decide whether to use the md5 hash or not.
3554  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
3555  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
3556  * error has occured.
3557  */
3558 static tng_function_status tng_molecules_block_write
3559                 (tng_trajectory_t tng_data,
3560                  const char hash_mode)
3561 {
3562     int len = 0, name_len, offset = 0;
3563     int64_t i, j, k, l;
3564     tng_molecule_t molecule;
3565     tng_chain_t chain;
3566     tng_residue_t residue;
3567     tng_atom_t atom;
3568     tng_bond_t bond;
3569     tng_gen_block_t block;
3570
3571     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
3572     {
3573         return(TNG_CRITICAL);
3574     }
3575
3576     tng_block_init(&block);
3577
3578     name_len = (int)strlen("MOLECULES");
3579
3580     block->name = malloc(name_len + 1);
3581     if(!block->name)
3582     {
3583         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
3584                 name_len+1, __FILE__, __LINE__);
3585         tng_block_destroy(&block);
3586         return(TNG_CRITICAL);
3587     }
3588
3589     strcpy(block->name, "MOLECULES");
3590     block->id = TNG_MOLECULES;
3591
3592     if(tng_molecules_block_len_calculate(tng_data, &block->block_contents_size) !=
3593         TNG_SUCCESS)
3594     {
3595         fprintf(stderr, "TNG library: Cannot calculate length of molecules block. %s: %d\n",
3596                 __FILE__, __LINE__);
3597         tng_block_destroy(&block);
3598         return(TNG_CRITICAL);
3599     }
3600
3601     block->block_contents = malloc(block->block_contents_size);
3602     if(!block->block_contents)
3603     {
3604         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3605                block->block_contents_size, __FILE__, __LINE__);
3606         tng_block_destroy(&block);
3607         return(TNG_CRITICAL);
3608     }
3609
3610     memcpy(block->block_contents+offset, &tng_data->n_molecules,
3611            sizeof(tng_data->n_molecules));
3612     if(tng_data->output_endianness_swap_func_64)
3613     {
3614         if(tng_data->output_endianness_swap_func_64(tng_data,
3615                                       (int64_t *)block->header_contents+offset)
3616             != TNG_SUCCESS)
3617         {
3618             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3619                     __FILE__, __LINE__);
3620         }
3621     }
3622     offset += sizeof(tng_data->n_molecules);
3623
3624     for(i = 0; i < tng_data->n_molecules; i++)
3625     {
3626         molecule = &tng_data->molecules[i];
3627         memcpy(block->block_contents+offset, &molecule->id,
3628                sizeof(molecule->id));
3629         if(tng_data->output_endianness_swap_func_64)
3630         {
3631             if(tng_data->output_endianness_swap_func_64(tng_data,
3632                                         (int64_t *)block->header_contents+offset)
3633                 != TNG_SUCCESS)
3634             {
3635                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3636                         __FILE__, __LINE__);
3637             }
3638         }
3639         offset += sizeof(molecule->id);
3640
3641 /*         fprintf(stderr, "TNG library: Wrote id: %"PRId64" offset: %d\n", molecule->id, offset); */
3642         len = tng_min_i((int)strlen(molecule->name) + 1, TNG_MAX_STR_LEN);
3643         strncpy(block->block_contents + offset, molecule->name, len);
3644         offset += len;
3645
3646         memcpy(block->block_contents+offset, &molecule->quaternary_str,
3647                sizeof(molecule->quaternary_str));
3648         if(tng_data->output_endianness_swap_func_64)
3649         {
3650             if(tng_data->output_endianness_swap_func_64(tng_data,
3651                                         (int64_t *)block->header_contents+offset)
3652                 != TNG_SUCCESS)
3653             {
3654                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3655                         __FILE__, __LINE__);
3656             }
3657         }
3658         offset += sizeof(molecule->quaternary_str);
3659
3660         if(!tng_data->var_num_atoms_flag)
3661         {
3662             memcpy(block->block_contents+offset,
3663                    &tng_data->molecule_cnt_list[i], sizeof(int64_t));
3664             if(tng_data->output_endianness_swap_func_64)
3665             {
3666                 if(tng_data->output_endianness_swap_func_64(tng_data,
3667                                             (int64_t *)block->header_contents+offset)
3668                     != TNG_SUCCESS)
3669                 {
3670                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3671                             __FILE__, __LINE__);
3672                 }
3673             }
3674             offset += sizeof(int64_t);
3675         }
3676
3677         memcpy(block->block_contents+offset, &molecule->n_chains,
3678                sizeof(molecule->n_chains));
3679         if(tng_data->output_endianness_swap_func_64)
3680         {
3681             if(tng_data->output_endianness_swap_func_64(tng_data,
3682                                         (int64_t *)block->header_contents+offset)
3683                 != TNG_SUCCESS)
3684             {
3685                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3686                         __FILE__, __LINE__);
3687             }
3688         }
3689         offset += sizeof(molecule->n_chains);
3690
3691         memcpy(block->block_contents+offset, &molecule->n_residues,
3692                sizeof(molecule->n_residues));
3693         if(tng_data->output_endianness_swap_func_64)
3694         {
3695             if(tng_data->output_endianness_swap_func_64(tng_data,
3696                                         (int64_t *)block->header_contents+offset)
3697                 != TNG_SUCCESS)
3698             {
3699                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3700                         __FILE__, __LINE__);
3701             }
3702         }
3703         offset += sizeof(molecule->n_residues);
3704
3705         memcpy(block->block_contents+offset, &molecule->n_atoms,
3706                sizeof(molecule->n_atoms));
3707         if(tng_data->output_endianness_swap_func_64)
3708         {
3709             if(tng_data->output_endianness_swap_func_64(tng_data,
3710                                         (int64_t *)block->header_contents+offset)
3711                 != TNG_SUCCESS)
3712             {
3713                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3714                         __FILE__, __LINE__);
3715             }
3716         }
3717         offset += sizeof(molecule->n_atoms);
3718
3719         if(molecule->n_chains > 0)
3720         {
3721             chain = molecule->chains;
3722             for(j = 0; j < molecule->n_chains; j++)
3723             {
3724                 tng_chain_data_write(tng_data, block, chain, &offset);
3725
3726                 residue = chain->residues;
3727                 for(k = 0; k < chain->n_residues; k++)
3728                 {
3729                     tng_residue_data_write(tng_data, block, residue, &offset);
3730
3731                     atom = molecule->atoms + residue->atoms_offset;
3732                     for(l = 0; l < residue->n_atoms; l++)
3733                     {
3734                         tng_atom_data_write(tng_data, block, atom, &offset);
3735
3736                         atom++;
3737                     }
3738                     residue++;
3739                 }
3740                 chain++;
3741             }
3742         }
3743         else
3744         {
3745             if(molecule->n_residues > 0)
3746             {
3747                 residue = molecule->residues;
3748                 for(k = 0; k < molecule->n_residues; k++)
3749                 {
3750                     tng_residue_data_write(tng_data, block, residue, &offset);
3751
3752                     atom = molecule->atoms + residue->atoms_offset;
3753                     for(l = 0; l < residue->n_atoms; l++)
3754                     {
3755                         tng_atom_data_write(tng_data, block, atom, &offset);
3756
3757                         atom++;
3758                     }
3759                     residue++;
3760                 }
3761             }
3762             else
3763             {
3764                 atom = molecule->atoms;
3765                 for(l = 0; l < molecule->n_atoms; l++)
3766                 {
3767                     tng_atom_data_write(tng_data, block, atom, &offset);
3768
3769                     atom++;
3770                 }
3771             }
3772         }
3773
3774         memcpy(block->block_contents+offset, &molecule->n_bonds,
3775                sizeof(molecule->n_bonds));
3776         if(tng_data->output_endianness_swap_func_64)
3777         {
3778             if(tng_data->output_endianness_swap_func_64(tng_data,
3779                                         (int64_t *)block->header_contents+offset)
3780                 != TNG_SUCCESS)
3781             {
3782                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3783                         __FILE__, __LINE__);
3784             }
3785         }
3786         offset += sizeof(molecule->n_bonds);
3787
3788         bond = molecule->bonds;
3789         for(j = 0; j < molecule->n_bonds; j++)
3790         {
3791             memcpy(block->block_contents+offset, &bond->from_atom_id,
3792                    sizeof(bond->from_atom_id));
3793             if(tng_data->output_endianness_swap_func_64)
3794             {
3795                 if(tng_data->output_endianness_swap_func_64(tng_data,
3796                                             (int64_t *)block->header_contents+offset)
3797                     != TNG_SUCCESS)
3798                 {
3799                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3800                             __FILE__, __LINE__);
3801                 }
3802             }
3803             offset += sizeof(bond->from_atom_id);
3804
3805             memcpy(block->block_contents+offset, &bond->to_atom_id,
3806                    sizeof(bond->to_atom_id));
3807             if(tng_data->output_endianness_swap_func_64)
3808             {
3809                 if(tng_data->output_endianness_swap_func_64(tng_data,
3810                                             (int64_t *)block->header_contents+offset)
3811                     != TNG_SUCCESS)
3812                 {
3813                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3814                             __FILE__, __LINE__);
3815                 }
3816             }
3817             offset += sizeof(bond->to_atom_id);
3818
3819             bond++;
3820         }
3821     }
3822
3823     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
3824     {
3825         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
3826                tng_data->output_file_path, __FILE__, __LINE__);
3827         tng_block_destroy(&block);
3828         return(TNG_CRITICAL);
3829     }
3830
3831     if(fwrite(block->block_contents, block->block_contents_size, 1,
3832               tng_data->output_file) != 1)
3833     {
3834         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n",
3835                __FILE__, __LINE__);
3836         tng_block_destroy(&block);
3837         return(TNG_CRITICAL);
3838     }
3839
3840     tng_block_destroy(&block);
3841
3842     return(TNG_SUCCESS);
3843 }
3844
3845 static tng_function_status tng_frame_set_block_len_calculate
3846                 (const tng_trajectory_t tng_data,
3847                  int64_t *len)
3848 {
3849     *len = sizeof(int64_t) * 8;
3850     *len += sizeof(double) * 2;
3851
3852     if(tng_data->var_num_atoms_flag)
3853     {
3854         *len += sizeof(int64_t) * tng_data->n_molecules;
3855     }
3856     return(TNG_SUCCESS);
3857 }
3858
3859 /** Read a frame set block. Update tng_data->current_trajectory_frame_set
3860  * @param tng_data is a trajectory data container.
3861  * @param block is a general block container.
3862  * @param hash_mode is an option to decide whether to use the md5 hash or not.
3863  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
3864  * compared to the md5 hash of the read contents to ensure valid data.
3865  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
3866  * error has occured.
3867  */
3868 static tng_function_status tng_frame_set_block_read
3869                 (tng_trajectory_t tng_data,
3870                  tng_gen_block_t block,
3871                  const char hash_mode)
3872 {
3873     long file_pos;
3874     int offset = 0;
3875     int64_t i, prev_n_particles;
3876     tng_bool same_hash;
3877     tng_trajectory_frame_set_t frame_set =
3878     &tng_data->current_trajectory_frame_set;
3879
3880     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
3881     {
3882         return(TNG_CRITICAL);
3883     }
3884
3885     if(block->block_contents)
3886     {
3887         free(block->block_contents);
3888     }
3889
3890     block->block_contents = malloc(block->block_contents_size);
3891     if(!block->block_contents)
3892     {
3893         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3894                block->block_contents_size, __FILE__, __LINE__);
3895         return(TNG_CRITICAL);
3896     }
3897
3898     /* Read the whole block into block_contents to be able to write it to
3899      * disk even if it cannot be interpreted. */
3900     if(fread(block->block_contents, block->block_contents_size, 1,
3901              tng_data->input_file) == 0)
3902     {
3903         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
3904         return(TNG_CRITICAL);
3905     }
3906
3907     /* FIXME: Does not check if the size of the contents matches the expected
3908      * size or if the contents can be read. */
3909
3910     file_pos = (int64_t)ftell(tng_data->input_file) -
3911                (long)(block->block_contents_size + block->header_contents_size);
3912
3913     if(hash_mode == TNG_USE_HASH)
3914     {
3915         tng_md5_hash_match_verify(block, &same_hash);
3916         if(same_hash != TNG_TRUE)
3917         {
3918             fprintf(stderr, "TNG library: Frame set block contents corrupt. File pos %ld Hashes do not match. "
3919                 "%s: %d\n",
3920                 file_pos, __FILE__, __LINE__);
3921     /*         return(TNG_FAILURE); */
3922         }
3923     }
3924
3925     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
3926
3927     tng_frame_set_particle_mapping_free(tng_data);
3928
3929     if(tng_data->first_trajectory_frame_set_input_file_pos <= 0)
3930     {
3931         tng_data->first_trajectory_frame_set_input_file_pos = file_pos;
3932     }
3933     /* FIXME: Should check the frame number instead of the file_pos, in case
3934      * frame sets are not in order */
3935     if(tng_data->last_trajectory_frame_set_input_file_pos < file_pos)
3936     {
3937         tng_data->last_trajectory_frame_set_input_file_pos = file_pos;
3938     }
3939
3940     memcpy(&frame_set->first_frame, block->block_contents,
3941            sizeof(frame_set->first_frame));
3942     if(tng_data->input_endianness_swap_func_64)
3943     {
3944         if(tng_data->input_endianness_swap_func_64(tng_data,
3945                                                    &frame_set->first_frame)
3946             != TNG_SUCCESS)
3947         {
3948             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3949                     __FILE__, __LINE__);
3950         }
3951     }
3952     offset += sizeof(frame_set->first_frame);
3953
3954     memcpy(&frame_set->n_frames, block->block_contents + offset,
3955            sizeof(frame_set->n_frames));
3956     if(tng_data->input_endianness_swap_func_64)
3957     {
3958         if(tng_data->input_endianness_swap_func_64(tng_data,
3959                                                    &frame_set->n_frames)
3960             != TNG_SUCCESS)
3961         {
3962             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3963                     __FILE__, __LINE__);
3964         }
3965     }
3966     offset += sizeof(frame_set->n_frames);
3967
3968     if(tng_data->var_num_atoms_flag)
3969     {
3970         prev_n_particles = frame_set->n_particles;
3971         frame_set->n_particles = 0;
3972         /* If the list of molecule counts has already been created assume that
3973          * it is of correct size. */
3974         if(!frame_set->molecule_cnt_list)
3975         {
3976                 frame_set->molecule_cnt_list =
3977                 malloc(sizeof(int64_t) * tng_data->n_molecules);
3978
3979                 if(!frame_set->molecule_cnt_list)
3980                 {
3981                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3982                            sizeof(int64_t) * tng_data->n_molecules,
3983                            __FILE__, __LINE__);
3984                     return(TNG_CRITICAL);
3985                 }
3986         }
3987         for(i = 0; i < tng_data->n_molecules; i++)
3988         {
3989             memcpy(&frame_set->molecule_cnt_list[i],
3990                    block->block_contents + offset,
3991                    sizeof(int64_t));
3992             if(tng_data->input_endianness_swap_func_64)
3993             {
3994                 if(tng_data->input_endianness_swap_func_64(tng_data,
3995                                               &frame_set->molecule_cnt_list[i])
3996                     != TNG_SUCCESS)
3997                 {
3998                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3999                             __FILE__, __LINE__);
4000                 }
4001             }
4002             offset += sizeof(int64_t);
4003             frame_set->n_particles += tng_data->molecules[i].n_atoms *
4004                                       frame_set->molecule_cnt_list[i];
4005         }
4006         if(prev_n_particles && frame_set->n_particles != prev_n_particles)
4007         {
4008             /* FIXME: Particle dependent data memory management */
4009         }
4010     }
4011
4012     memcpy(&frame_set->next_frame_set_file_pos,
4013            block->block_contents + offset,
4014            sizeof(frame_set->next_frame_set_file_pos));
4015     if(tng_data->input_endianness_swap_func_64)
4016     {
4017         if(tng_data->input_endianness_swap_func_64(tng_data,
4018                                            &frame_set->next_frame_set_file_pos)
4019             != TNG_SUCCESS)
4020         {
4021             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4022                     __FILE__, __LINE__);
4023         }
4024     }
4025     offset += sizeof(frame_set->next_frame_set_file_pos);
4026
4027     memcpy(&frame_set->prev_frame_set_file_pos,
4028            block->block_contents + offset,
4029            sizeof(frame_set->prev_frame_set_file_pos));
4030     if(tng_data->input_endianness_swap_func_64)
4031     {
4032         if(tng_data->input_endianness_swap_func_64(tng_data,
4033                                            &frame_set->prev_frame_set_file_pos)
4034             != TNG_SUCCESS)
4035         {
4036             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4037                     __FILE__, __LINE__);
4038         }
4039     }
4040     offset += sizeof(frame_set->prev_frame_set_file_pos);
4041
4042     memcpy(&frame_set->medium_stride_next_frame_set_file_pos,
4043            block->block_contents + offset,
4044            sizeof(frame_set->medium_stride_next_frame_set_file_pos));
4045     if(tng_data->input_endianness_swap_func_64)
4046     {
4047         if(tng_data->input_endianness_swap_func_64(tng_data,
4048                              &frame_set->medium_stride_next_frame_set_file_pos)
4049             != TNG_SUCCESS)
4050         {
4051             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4052                     __FILE__, __LINE__);
4053         }
4054     }
4055     offset += sizeof(frame_set->medium_stride_next_frame_set_file_pos);
4056
4057     memcpy(&frame_set->medium_stride_prev_frame_set_file_pos,
4058            block->block_contents + offset,
4059            sizeof(frame_set->medium_stride_prev_frame_set_file_pos));
4060     if(tng_data->input_endianness_swap_func_64)
4061     {
4062         if(tng_data->input_endianness_swap_func_64(tng_data,
4063                              &frame_set->medium_stride_prev_frame_set_file_pos)
4064             != TNG_SUCCESS)
4065         {
4066             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4067                     __FILE__, __LINE__);
4068         }
4069     }
4070     offset += sizeof(frame_set->medium_stride_prev_frame_set_file_pos);
4071
4072     memcpy(&frame_set->long_stride_next_frame_set_file_pos,
4073            block->block_contents + offset,
4074            sizeof(frame_set->long_stride_next_frame_set_file_pos));
4075     if(tng_data->input_endianness_swap_func_64)
4076     {
4077         if(tng_data->input_endianness_swap_func_64(tng_data,
4078                                &frame_set->long_stride_next_frame_set_file_pos)
4079             != TNG_SUCCESS)
4080         {
4081             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4082                     __FILE__, __LINE__);
4083         }
4084     }
4085     offset += sizeof(frame_set->long_stride_next_frame_set_file_pos);
4086
4087     memcpy(&frame_set->long_stride_prev_frame_set_file_pos,
4088            block->block_contents + offset,
4089            sizeof(frame_set->long_stride_prev_frame_set_file_pos));
4090     if(tng_data->input_endianness_swap_func_64)
4091     {
4092         if(tng_data->input_endianness_swap_func_64(tng_data,
4093                                &frame_set->long_stride_prev_frame_set_file_pos)
4094             != TNG_SUCCESS)
4095         {
4096             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4097                     __FILE__, __LINE__);
4098         }
4099     }
4100     offset += sizeof(frame_set->long_stride_prev_frame_set_file_pos);
4101
4102     if(block->block_version >= 3)
4103     {
4104         memcpy(&frame_set->first_frame_time,
4105             block->block_contents + offset,
4106             sizeof(frame_set->first_frame_time));
4107         if(tng_data->input_endianness_swap_func_64)
4108         {
4109             if(tng_data->input_endianness_swap_func_64(tng_data,
4110                                 (int64_t *)&frame_set->first_frame_time)
4111                 != TNG_SUCCESS)
4112             {
4113                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4114                         __FILE__, __LINE__);
4115             }
4116         }
4117         offset += sizeof(frame_set->first_frame_time);
4118
4119         memcpy(&tng_data->time_per_frame,
4120             block->block_contents + offset,
4121             sizeof(tng_data->time_per_frame));
4122         if(tng_data->input_endianness_swap_func_64)
4123         {
4124             if(tng_data->input_endianness_swap_func_64(tng_data,
4125                                 (int64_t *)&tng_data->time_per_frame)
4126                 != TNG_SUCCESS)
4127             {
4128                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4129                         __FILE__, __LINE__);
4130             }
4131         }
4132     }
4133     else
4134     {
4135         frame_set->first_frame_time = -1;
4136         tng_data->time_per_frame = -1;
4137     }
4138
4139     /* If the output file and the input files are the same the number of
4140      * frames in the file are the same number as has just been read.
4141      * This is updated here to later on see if there have been new frames
4142      * added and thereby the frame set needs to be rewritten. */
4143     if(tng_data->output_file == tng_data->input_file)
4144     {
4145         frame_set->n_written_frames = frame_set->n_frames;
4146     }
4147
4148     return(TNG_SUCCESS);
4149 }
4150
4151 /** Write tng_data->current_trajectory_frame_set to file
4152  * @param tng_data is a trajectory data container.
4153  * @param block is a general block container.
4154  * @param hash_mode is an option to decide whether to use the md5 hash or not.
4155  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
4156  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
4157  * error has occured.
4158  */
4159 static tng_function_status tng_frame_set_block_write
4160                 (tng_trajectory_t tng_data,
4161                  tng_gen_block_t block,
4162                  const char hash_mode)
4163 {
4164     char *temp_name;
4165     int64_t i;
4166     int offset = 0;
4167     unsigned int name_len;
4168     tng_trajectory_frame_set_t frame_set =
4169     &tng_data->current_trajectory_frame_set;
4170
4171     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
4172     {
4173         return(TNG_CRITICAL);
4174     }
4175
4176     name_len = (int)strlen("TRAJECTORY FRAME SET");
4177
4178     if(!block->name || strlen(block->name) < name_len)
4179     {
4180         temp_name = realloc(block->name, name_len + 1);
4181         if(!temp_name)
4182         {
4183             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
4184                    name_len+1, __FILE__, __LINE__);
4185             free(block->name);
4186             block->name = 0;
4187             return(TNG_CRITICAL);
4188         }
4189         block->name = temp_name;
4190     }
4191     strcpy(block->name, "TRAJECTORY FRAME SET");
4192     block->id = TNG_TRAJECTORY_FRAME_SET;
4193
4194     if(tng_frame_set_block_len_calculate(tng_data, &block->block_contents_size) !=
4195         TNG_SUCCESS)
4196     {
4197         fprintf(stderr, "TNG library: Cannot calculate length of frame set block. %s: %d\n",
4198                 __FILE__, __LINE__);
4199         return(TNG_CRITICAL);
4200     }
4201
4202     if(block->block_contents)
4203     {
4204         free(block->block_contents);
4205     }
4206     block->block_contents = malloc(block->block_contents_size);
4207     if(!block->block_contents)
4208     {
4209         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4210                block->block_contents_size, __FILE__, __LINE__);
4211         return(TNG_CRITICAL);
4212     }
4213
4214     memcpy(block->block_contents, &frame_set->first_frame,
4215            sizeof(frame_set->first_frame));
4216     if(tng_data->output_endianness_swap_func_64)
4217     {
4218         if(tng_data->output_endianness_swap_func_64(tng_data,
4219                                       (int64_t *)block->header_contents+offset)
4220             != TNG_SUCCESS)
4221         {
4222             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4223                     __FILE__, __LINE__);
4224         }
4225     }
4226     offset += sizeof(frame_set->first_frame);
4227
4228     memcpy(block->block_contents+offset, &frame_set->n_frames,
4229            sizeof(frame_set->n_frames));
4230     if(tng_data->output_endianness_swap_func_64)
4231     {
4232         if(tng_data->output_endianness_swap_func_64(tng_data,
4233                                       (int64_t *)block->header_contents+offset)
4234             != TNG_SUCCESS)
4235         {
4236             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4237                     __FILE__, __LINE__);
4238         }
4239     }
4240     offset += sizeof(frame_set->n_frames);
4241
4242     if(tng_data->var_num_atoms_flag)
4243     {
4244         for(i = 0; i < tng_data->n_molecules; i++)
4245         {
4246             memcpy(block->block_contents+offset,
4247                    &frame_set->molecule_cnt_list[i],
4248                    sizeof(int64_t));
4249             if(tng_data->output_endianness_swap_func_64)
4250             {
4251                 if(tng_data->output_endianness_swap_func_64(tng_data,
4252                                             (int64_t *)block->header_contents+offset)
4253                     != TNG_SUCCESS)
4254                 {
4255                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4256                             __FILE__, __LINE__);
4257                 }
4258             }
4259             offset += sizeof(int64_t);
4260         }
4261     }
4262
4263
4264     memcpy(block->block_contents+offset, &frame_set->next_frame_set_file_pos,
4265            sizeof(frame_set->next_frame_set_file_pos));
4266     if(tng_data->output_endianness_swap_func_64)
4267     {
4268         if(tng_data->output_endianness_swap_func_64(tng_data,
4269                                       (int64_t *)block->header_contents+offset)
4270             != TNG_SUCCESS)
4271         {
4272             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4273                     __FILE__, __LINE__);
4274         }
4275     }
4276     offset += sizeof(frame_set->next_frame_set_file_pos);
4277
4278     memcpy(block->block_contents+offset, &frame_set->prev_frame_set_file_pos,
4279            sizeof(frame_set->prev_frame_set_file_pos));
4280     if(tng_data->output_endianness_swap_func_64)
4281     {
4282         if(tng_data->output_endianness_swap_func_64(tng_data,
4283                                       (int64_t *)block->header_contents+offset)
4284             != TNG_SUCCESS)
4285         {
4286             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4287                     __FILE__, __LINE__);
4288         }
4289     }
4290     offset += sizeof(frame_set->prev_frame_set_file_pos);
4291
4292     memcpy(block->block_contents+offset,
4293            &frame_set->medium_stride_next_frame_set_file_pos,
4294            sizeof(frame_set->medium_stride_next_frame_set_file_pos));
4295     if(tng_data->output_endianness_swap_func_64)
4296     {
4297         if(tng_data->output_endianness_swap_func_64(tng_data,
4298                                       (int64_t *)block->header_contents+offset)
4299             != TNG_SUCCESS)
4300         {
4301             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4302                     __FILE__, __LINE__);
4303         }
4304     }
4305     offset += sizeof(frame_set->medium_stride_next_frame_set_file_pos);
4306
4307     memcpy(block->block_contents+offset,
4308            &frame_set->medium_stride_prev_frame_set_file_pos,
4309            sizeof(frame_set->medium_stride_prev_frame_set_file_pos));
4310     if(tng_data->output_endianness_swap_func_64)
4311     {
4312         if(tng_data->output_endianness_swap_func_64(tng_data,
4313                                       (int64_t *)block->header_contents+offset)
4314             != TNG_SUCCESS)
4315         {
4316             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4317                     __FILE__, __LINE__);
4318         }
4319     }
4320     offset += sizeof(frame_set->medium_stride_prev_frame_set_file_pos);
4321
4322     memcpy(block->block_contents+offset,
4323            &frame_set->long_stride_next_frame_set_file_pos,
4324            sizeof(frame_set->long_stride_next_frame_set_file_pos));
4325     if(tng_data->output_endianness_swap_func_64)
4326     {
4327         if(tng_data->output_endianness_swap_func_64(tng_data,
4328                                       (int64_t *)block->header_contents+offset)
4329             != TNG_SUCCESS)
4330         {
4331             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4332                     __FILE__, __LINE__);
4333         }
4334     }
4335     offset += sizeof(frame_set->long_stride_next_frame_set_file_pos);
4336
4337     memcpy(block->block_contents+offset,
4338            &frame_set->long_stride_prev_frame_set_file_pos,
4339            sizeof(frame_set->long_stride_prev_frame_set_file_pos));
4340     if(tng_data->output_endianness_swap_func_64)
4341     {
4342         if(tng_data->output_endianness_swap_func_64(tng_data,
4343                                       (int64_t *)block->header_contents+offset)
4344             != TNG_SUCCESS)
4345         {
4346             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4347                     __FILE__, __LINE__);
4348         }
4349     }
4350     offset += sizeof(frame_set->long_stride_prev_frame_set_file_pos);
4351
4352     memcpy(block->block_contents+offset,
4353            &frame_set->first_frame_time,
4354            sizeof(frame_set->first_frame_time));
4355     if(tng_data->output_endianness_swap_func_64)
4356     {
4357         if(tng_data->output_endianness_swap_func_64(tng_data,
4358                                       (int64_t *)block->header_contents+offset)
4359             != TNG_SUCCESS)
4360         {
4361             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4362                     __FILE__, __LINE__);
4363         }
4364     }
4365     offset += sizeof(frame_set->first_frame_time);
4366
4367     memcpy(block->block_contents+offset,
4368            &tng_data->time_per_frame,
4369            sizeof(tng_data->time_per_frame));
4370     if(tng_data->output_endianness_swap_func_64)
4371     {
4372         if(tng_data->output_endianness_swap_func_64(tng_data,
4373                                       (int64_t *)block->header_contents+offset)
4374             != TNG_SUCCESS)
4375         {
4376             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4377                     __FILE__, __LINE__);
4378         }
4379     }
4380
4381     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
4382     {
4383         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
4384                tng_data->output_file_path, __FILE__, __LINE__);
4385         return(TNG_CRITICAL);
4386     }
4387
4388     if(fwrite(block->block_contents, block->block_contents_size, 1,
4389               tng_data->output_file) != 1)
4390     {
4391         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__, __LINE__);
4392         return(TNG_CRITICAL);
4393     }
4394
4395     return(TNG_SUCCESS);
4396 }
4397
4398 static tng_function_status tng_trajectory_mapping_block_len_calculate
4399                 (const tng_trajectory_t tng_data,
4400                  const int64_t n_particles,
4401                  int64_t *len)
4402 {
4403     (void)tng_data;
4404     *len = sizeof(int64_t) * (2 + n_particles);
4405
4406     return(TNG_SUCCESS);
4407 }
4408
4409 /** Read an atom mappings block (translating between real atom indexes and how
4410  *  the atom info is written in this frame set).
4411  * @param tng_data is a trajectory data container.
4412  * @param block is a general block container.
4413  * @param hash_mode is an option to decide whether to use the md5 hash or not.
4414  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
4415  * compared to the md5 hash of the read contents to ensure valid data.
4416  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
4417  * error has occured.
4418  */
4419 static tng_function_status tng_trajectory_mapping_block_read
4420                 (tng_trajectory_t tng_data,
4421                  tng_gen_block_t block,
4422                  const char hash_mode)
4423 {
4424     int64_t i;
4425     int offset = 0;
4426     tng_bool same_hash;
4427     tng_trajectory_frame_set_t frame_set =
4428     &tng_data->current_trajectory_frame_set;
4429
4430     tng_particle_mapping_t mapping, mappings;
4431
4432     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
4433     {
4434         return(TNG_CRITICAL);
4435     }
4436
4437     if(block->block_contents)
4438     {
4439         free(block->block_contents);
4440     }
4441
4442     block->block_contents = malloc(block->block_contents_size);
4443     if(!block->block_contents)
4444     {
4445         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4446                block->block_contents_size, __FILE__, __LINE__);
4447         return(TNG_CRITICAL);
4448     }
4449
4450     /* Read the whole block into block_contents to be able to write it to disk
4451      *  even if it cannot be interpreted. */
4452     if(fread(block->block_contents, block->block_contents_size, 1,
4453         tng_data->input_file) == 0)
4454     {
4455         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
4456         return(TNG_CRITICAL);
4457     }
4458
4459     /* FIXME: Does not check if the size of the contents matches the expected
4460      * size or if the contents can be read. */
4461
4462     if(hash_mode == TNG_USE_HASH)
4463     {
4464         tng_md5_hash_match_verify(block, &same_hash);
4465         if(same_hash != TNG_TRUE)
4466         {
4467             fprintf(stderr, "TNG library: Particle mapping block contents corrupt. Hashes do not match. "
4468                 "%s: %d\n",
4469                 __FILE__, __LINE__);
4470     /*         return(TNG_FAILURE); */
4471         }
4472     }
4473
4474     frame_set->n_mapping_blocks++;
4475     mappings = realloc(frame_set->mappings,
4476                        sizeof(struct tng_particle_mapping) *
4477                        frame_set->n_mapping_blocks);
4478     if(!mappings)
4479     {
4480         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4481                block->block_contents_size, __FILE__, __LINE__);
4482         free(frame_set->mappings);
4483         frame_set->mappings = 0;
4484         return(TNG_CRITICAL);
4485     }
4486     frame_set->mappings = mappings;
4487     mapping = &mappings[frame_set->n_mapping_blocks - 1];
4488
4489
4490     memcpy(&mapping->num_first_particle, block->block_contents+offset,
4491            sizeof(mapping->num_first_particle));
4492     if(tng_data->input_endianness_swap_func_64)
4493     {
4494         if(tng_data->input_endianness_swap_func_64(tng_data,
4495                                                    &mapping->num_first_particle)
4496             != TNG_SUCCESS)
4497         {
4498             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4499                     __FILE__, __LINE__);
4500         }
4501     }
4502     offset += sizeof(mapping->num_first_particle);
4503
4504     memcpy(&mapping->n_particles, block->block_contents+offset,
4505            sizeof(mapping->n_particles));
4506     if(tng_data->input_endianness_swap_func_64)
4507     {
4508         if(tng_data->input_endianness_swap_func_64(tng_data,
4509                                                    &mapping->n_particles)
4510             != TNG_SUCCESS)
4511         {
4512             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4513                     __FILE__, __LINE__);
4514         }
4515     }
4516     offset += sizeof(mapping->n_particles);
4517
4518     mapping->real_particle_numbers = malloc(mapping->n_particles *
4519                                             sizeof(int64_t));
4520     if(!mapping->real_particle_numbers)
4521     {
4522         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4523                 mapping->n_particles * sizeof(int64_t), __FILE__, __LINE__);
4524         return(TNG_CRITICAL);
4525     }
4526
4527     /* If the byte order needs to be swapped the data must be read one value at
4528      * a time and swapped */
4529     if(tng_data->input_endianness_swap_func_64)
4530     {
4531         for(i = 0; i < mapping->n_particles; i++)
4532         {
4533             memcpy(&mapping->real_particle_numbers[i],
4534                     block->block_contents + offset,
4535                     sizeof(int64_t));
4536             if(tng_data->input_endianness_swap_func_64(tng_data,
4537                                             &mapping->real_particle_numbers[i])
4538                 != TNG_SUCCESS)
4539             {
4540                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4541                         __FILE__, __LINE__);
4542             }
4543             offset += sizeof(int64_t);
4544         }
4545     }
4546     /* Otherwise the data can be read all at once */
4547     else
4548     {
4549         memcpy(mapping->real_particle_numbers, block->block_contents + offset,
4550                mapping->n_particles * sizeof(int64_t));
4551     }
4552
4553
4554     return(TNG_SUCCESS);
4555 }
4556
4557 /** Write the atom mappings of the current trajectory frame set
4558  * @param tng_data is a trajectory data container.
4559  * @param block is a general block container.
4560  * @param mapping_block_nr is the index of the mapping block to write.
4561  * @param hash_mode is an option to decide whether to use the md5 hash or not.
4562  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
4563  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
4564  * has occurred or TNG_CRITICAL (2) if a major error has occured.
4565  */
4566 static tng_function_status tng_trajectory_mapping_block_write
4567                 (tng_trajectory_t tng_data,
4568                  tng_gen_block_t block,
4569                  int mapping_block_nr,
4570                  const char hash_mode)
4571 {
4572     char *temp_name;
4573     int i, offset = 0;
4574     unsigned int name_len;
4575     tng_particle_mapping_t mapping =
4576     &tng_data->current_trajectory_frame_set.mappings[mapping_block_nr];
4577
4578     if(mapping_block_nr >=
4579        tng_data->current_trajectory_frame_set.n_mapping_blocks)
4580     {
4581         fprintf(stderr, "TNG library: Mapping block index out of bounds. %s: %d\n",
4582                __FILE__, __LINE__);
4583         return(TNG_FAILURE);
4584     }
4585
4586     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
4587     {
4588         return(TNG_CRITICAL);
4589     }
4590
4591     name_len = (int)strlen("PARTICLE MAPPING");
4592
4593     if(!block->name || strlen(block->name) < name_len)
4594     {
4595         temp_name = realloc(block->name, name_len + 1);
4596         if(!temp_name)
4597         {
4598             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
4599                    name_len+1, __FILE__, __LINE__);
4600             free(block->name);
4601             block->name = 0;
4602             return(TNG_CRITICAL);
4603         }
4604         block->name = temp_name;
4605     }
4606     strcpy(block->name, "PARTICLE MAPPING");
4607     block->id = TNG_PARTICLE_MAPPING;
4608
4609     if(tng_trajectory_mapping_block_len_calculate(tng_data,
4610                                                   mapping->n_particles,
4611                                                   &block->block_contents_size) !=
4612         TNG_SUCCESS)
4613     {
4614         fprintf(stderr, "TNG library: Cannot calculate length of atom mapping block. %s: %d\n",
4615                 __FILE__, __LINE__);
4616         return(TNG_CRITICAL);
4617     }
4618
4619     if(block->block_contents)
4620     {
4621         free(block->block_contents);
4622     }
4623     block->block_contents = malloc(block->block_contents_size);
4624     if(!block->block_contents)
4625     {
4626         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4627                block->block_contents_size, __FILE__, __LINE__);
4628         return(TNG_CRITICAL);
4629     }
4630
4631     memcpy(block->block_contents, &mapping->num_first_particle,
4632            sizeof(mapping->num_first_particle));
4633     if(tng_data->output_endianness_swap_func_64)
4634     {
4635         if(tng_data->output_endianness_swap_func_64(tng_data,
4636                                       (int64_t *)block->header_contents+offset)
4637             != TNG_SUCCESS)
4638         {
4639             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4640                     __FILE__, __LINE__);
4641         }
4642     }
4643     offset += sizeof(mapping->num_first_particle);
4644
4645     memcpy(block->block_contents+offset, &mapping->n_particles,
4646            sizeof(mapping->n_particles));
4647     if(tng_data->output_endianness_swap_func_64)
4648     {
4649         if(tng_data->output_endianness_swap_func_64(tng_data,
4650                                       (int64_t *)block->header_contents+offset)
4651             != TNG_SUCCESS)
4652         {
4653             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4654                     __FILE__, __LINE__);
4655         }
4656     }
4657     offset += sizeof(mapping->n_particles);
4658
4659     if(tng_data->output_endianness_swap_func_64)
4660     {
4661         for(i = 0; i < mapping->n_particles; i++)
4662         {
4663             memcpy(block->block_contents+offset, &mapping->real_particle_numbers[i],
4664                 sizeof(int64_t));
4665             if(tng_data->output_endianness_swap_func_64(tng_data,
4666                                         (int64_t *)block->header_contents+offset)
4667                 != TNG_SUCCESS)
4668             {
4669                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4670                         __FILE__, __LINE__);
4671             }
4672             offset += sizeof(int64_t);
4673         }
4674     }
4675     else
4676     {
4677         memcpy(block->block_contents+offset, mapping->real_particle_numbers,
4678                mapping->n_particles * sizeof(int64_t));
4679     }
4680
4681
4682     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
4683     {
4684         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
4685                tng_data->output_file_path, __FILE__, __LINE__);
4686         return(TNG_CRITICAL);
4687     }
4688
4689     if(fwrite(block->block_contents, block->block_contents_size, 1,
4690               tng_data->output_file) != 1)
4691     {
4692         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__, __LINE__);
4693         return(TNG_CRITICAL);
4694     }
4695
4696     return(TNG_SUCCESS);
4697 }
4698
4699 /** Prepare a block for storing particle data
4700  * @param tng_data is a trajectory data container.
4701  * @param block_type_flag specifies if this is a trajectory block or a
4702  * non-trajectory block. (TNG_TRAJECTORY_BLOCK or TNG_NON_TRAJECTORY_BLOCK)
4703  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
4704  * error has occured.
4705  */
4706 static tng_function_status tng_particle_data_block_create
4707                 (tng_trajectory_t tng_data,
4708                  const char block_type_flag)
4709 {
4710     tng_trajectory_frame_set_t frame_set =
4711     &tng_data->current_trajectory_frame_set;
4712
4713     tng_particle_data_t data;
4714
4715     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
4716     {
4717         frame_set->n_particle_data_blocks++;
4718         data = realloc(frame_set->tr_particle_data,
4719                     sizeof(struct tng_particle_data) *
4720                     frame_set->n_particle_data_blocks);
4721         if(!data)
4722         {
4723             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
4724                 sizeof(struct tng_particle_data) *
4725                 frame_set->n_particle_data_blocks,
4726                 __FILE__, __LINE__);
4727             free(frame_set->tr_particle_data);
4728             frame_set->tr_particle_data = 0;
4729             return(TNG_CRITICAL);
4730         }
4731         frame_set->tr_particle_data = data;
4732     }
4733     else
4734     {
4735         tng_data->n_particle_data_blocks++;
4736         data = realloc(tng_data->non_tr_particle_data,
4737                         sizeof(struct tng_particle_data) *
4738                         tng_data->n_particle_data_blocks);
4739         if(!data)
4740         {
4741             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
4742                     sizeof(struct tng_particle_data) *
4743                     tng_data->n_particle_data_blocks,
4744                     __FILE__, __LINE__);
4745             free(tng_data->non_tr_particle_data);
4746             tng_data->non_tr_particle_data = 0;
4747             return(TNG_CRITICAL);
4748         }
4749         tng_data->non_tr_particle_data = data;
4750     }
4751
4752     return(TNG_SUCCESS);
4753 }
4754
4755 static tng_function_status tng_compress(tng_trajectory_t tng_data,
4756                                         tng_gen_block_t block,
4757                                         const int64_t n_frames,
4758                                         const int64_t n_particles,
4759                                         const char type,
4760                                         void *start_pos)
4761 {
4762     int nalgo;
4763     int new_len;
4764     int *alt_algo = 0;
4765     char *dest, *temp;
4766     int64_t algo_find_n_frames;
4767     unsigned long offset;
4768     float f_precision;
4769     double d_precision;
4770
4771     if(block->id != TNG_TRAJ_POSITIONS &&
4772        block->id != TNG_TRAJ_VELOCITIES)
4773     {
4774         fprintf(stderr, "TNG library: Can only compress positions and velocities with the "
4775                "TNG method. %s: %d\n", __FILE__, __LINE__);
4776         return(TNG_FAILURE);
4777     }
4778     if(type != TNG_FLOAT_DATA && type != TNG_DOUBLE_DATA)
4779     {
4780         fprintf(stderr, "TNG library: Data type not supported. %s: %d\n", __FILE__, __LINE__);
4781         return(TNG_FAILURE);
4782     }
4783
4784     if(n_frames <= 0 || n_particles <= 0)
4785     {
4786         fprintf(stderr, "TNG library: Missing frames or particles. Cannot compress data "
4787                "with the TNG method. %s: %d\n", __FILE__, __LINE__);
4788         return(TNG_FAILURE);
4789     }
4790
4791     f_precision = 1/(float)tng_data->compression_precision;
4792     d_precision = 1/tng_data->compression_precision;
4793
4794     if(block->id == TNG_TRAJ_POSITIONS)
4795     {
4796         /* If there is only one frame in this frame set and there might be more
4797          * do not store the algorithm as the compression algorithm, but find
4798          * the best one without storing it */
4799         if(n_frames == 1 && tng_data->frame_set_n_frames > 1)
4800         {
4801             nalgo = tng_compress_nalgo();
4802             alt_algo=malloc(nalgo * sizeof *tng_data->compress_algo_pos);
4803             if(type == TNG_FLOAT_DATA)
4804             {
4805                 dest = tng_compress_pos_float_find_algo(start_pos, (int)n_particles,
4806                                                         (int)n_frames,
4807                                                         f_precision,
4808                                                         0, alt_algo,
4809                                                         &new_len);
4810
4811             }
4812             else
4813             {
4814                 dest = tng_compress_pos_find_algo(start_pos, (int)n_particles,
4815                                            (int)n_frames,
4816                                            d_precision,
4817                                            0, alt_algo,
4818                                            &new_len);
4819             }
4820         }
4821         else if(!tng_data->compress_algo_pos)
4822         {
4823             if(n_frames > 10)
4824             {
4825                 algo_find_n_frames = 5;
4826             }
4827             else
4828             {
4829                 algo_find_n_frames = n_frames;
4830             }
4831
4832             nalgo = tng_compress_nalgo();
4833             tng_data->compress_algo_pos=malloc(nalgo *
4834                                            sizeof *tng_data->compress_algo_pos);
4835             if(type == TNG_FLOAT_DATA)
4836             {
4837                 dest = tng_compress_pos_float_find_algo(start_pos, (int)n_particles,
4838                                                         (int)algo_find_n_frames,
4839                                                         f_precision,
4840                                                         0, tng_data->
4841                                                         compress_algo_pos,
4842                                                         &new_len);
4843
4844                 if(algo_find_n_frames < n_frames)
4845                 {
4846                     dest = tng_compress_pos_float(start_pos, (int)n_particles,
4847                                                   (int)n_frames,
4848                                                   f_precision,
4849                                                   0, tng_data->compress_algo_pos,
4850                                                   &new_len);
4851                 }
4852             }
4853             else
4854             {
4855                 dest = tng_compress_pos_find_algo(start_pos, (int)n_particles,
4856                                            (int)algo_find_n_frames,
4857                                            d_precision,
4858                                            0, tng_data->
4859                                            compress_algo_pos,
4860                                            &new_len);
4861
4862                 if(algo_find_n_frames < n_frames)
4863                 {
4864                     dest = tng_compress_pos(start_pos, (int)n_particles,
4865                                             (int)n_frames,
4866                                             d_precision, 0,
4867                                             tng_data->compress_algo_pos,
4868                                             &new_len);
4869                 }
4870             }
4871         }
4872         else
4873         {
4874             if(type == TNG_FLOAT_DATA)
4875             {
4876                 dest = tng_compress_pos_float(start_pos, (int)n_particles,
4877                                               (int)n_frames,
4878                                               f_precision, 0,
4879                                               tng_data->compress_algo_pos, &new_len);
4880             }
4881             else
4882             {
4883                 dest = tng_compress_pos(start_pos, (int)n_particles,
4884                                         (int)n_frames,
4885                                         d_precision, 0,
4886                                         tng_data->compress_algo_pos,
4887                                         &new_len);
4888             }
4889         }
4890     }
4891     else if(block->id == TNG_TRAJ_VELOCITIES)
4892     {
4893         /* If there is only one frame in this frame set and there might be more
4894          * do not store the algorithm as the compression algorithm, but find
4895          * the best one without storing it */
4896         if(n_frames == 1 && tng_data->frame_set_n_frames > 1)
4897         {
4898             nalgo = tng_compress_nalgo();
4899             alt_algo=malloc(nalgo * sizeof *tng_data->compress_algo_pos);
4900             if(type == TNG_FLOAT_DATA)
4901             {
4902                 dest = tng_compress_vel_float_find_algo(start_pos, (int)n_particles,
4903                                                         (int)n_frames,
4904                                                         f_precision,
4905                                                         0, alt_algo,
4906                                                         &new_len);
4907
4908             }
4909             else
4910             {
4911                 dest = tng_compress_vel_find_algo(start_pos, (int)n_particles,
4912                                                   (int)n_frames,
4913                                                   d_precision,
4914                                                   0, alt_algo,
4915                                                   &new_len);
4916             }
4917         }
4918         else if(!tng_data->compress_algo_vel)
4919         {
4920             if(n_frames > 10)
4921             {
4922                 algo_find_n_frames = 5;
4923             }
4924             else
4925             {
4926                 algo_find_n_frames = n_frames;
4927             }
4928
4929             nalgo = tng_compress_nalgo();
4930             tng_data->compress_algo_vel=malloc(nalgo *
4931                                            sizeof *tng_data->compress_algo_vel);
4932
4933             if(type == TNG_FLOAT_DATA)
4934             {
4935                 dest = tng_compress_vel_float_find_algo(start_pos, (int)n_particles,
4936                                                         (int)algo_find_n_frames,
4937                                                         f_precision,
4938                                                         0, tng_data->
4939                                                         compress_algo_vel,
4940                                                         &new_len);
4941                 if(algo_find_n_frames < n_frames)
4942                 {
4943                     dest = tng_compress_vel_float(start_pos, (int)n_particles,
4944                                                   (int)n_frames,
4945                                                   f_precision,
4946                                                   0, tng_data->compress_algo_vel,
4947                                                   &new_len);
4948                 }
4949             }
4950             else
4951             {
4952                 dest = tng_compress_vel_find_algo(start_pos, (int)n_particles,
4953                                                   (int)algo_find_n_frames,
4954                                                   d_precision,
4955                                                   0, tng_data->
4956                                                   compress_algo_vel,
4957                                                   &new_len);
4958                 if(algo_find_n_frames < n_frames)
4959                 {
4960                     dest = tng_compress_vel(start_pos, (int)n_particles,
4961                                             (int)n_frames,
4962                                             d_precision,
4963                                             0, tng_data->compress_algo_vel,
4964                                             &new_len);
4965                 }
4966             }
4967         }
4968         else
4969         {
4970             if(type == TNG_FLOAT_DATA)
4971             {
4972                 dest = tng_compress_vel_float(start_pos, (int)n_particles,
4973                                               (int)n_frames,
4974                                               f_precision,
4975                                               0, tng_data->
4976                                               compress_algo_vel,
4977                                               &new_len);
4978             }
4979             else
4980             {
4981                 dest = tng_compress_vel(start_pos, (int)n_particles,
4982                                         (int)n_frames,
4983                                         d_precision,
4984                                         0, tng_data->
4985                                         compress_algo_vel,
4986                                         &new_len);
4987             }
4988         }
4989     }
4990     else
4991     {
4992         fprintf(stderr, "TNG library: Can only compress positions and velocities using TNG-MF1 algorithms.\n");
4993         return(TNG_FAILURE);
4994     }
4995
4996     offset = (unsigned long)((char *)start_pos - block->block_contents);
4997
4998     if(alt_algo)
4999     {
5000         free(alt_algo);
5001     }
5002
5003     block->block_contents_size = new_len + offset;
5004
5005     temp = realloc(block->block_contents, block->block_contents_size);
5006     if(!temp)
5007     {
5008         free(block->block_contents);
5009         block->block_contents = 0;
5010         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5011                block->block_contents_size, __FILE__, __LINE__);
5012         return(TNG_CRITICAL);
5013     }
5014     block->block_contents = temp;
5015     if(dest)
5016     {
5017         memcpy(temp + offset, dest, new_len);
5018         free(dest);
5019     }
5020     else
5021     {
5022         fprintf(stderr, "TNG library: Error during TNG compression. %s: %d\n", __FILE__, __LINE__);
5023         return(TNG_FAILURE);
5024     }
5025
5026     return(TNG_SUCCESS);
5027 }
5028
5029 static tng_function_status tng_uncompress(tng_trajectory_t tng_data,
5030                                           tng_gen_block_t block,
5031                                           const char type,
5032                                           void *start_pos,
5033                                           const unsigned long uncompressed_len)
5034 {
5035     char *temp;
5036     double *d_dest = 0;
5037     float *f_dest = 0;
5038     unsigned long offset;
5039     int result;
5040     (void)tng_data;
5041
5042     TNG_ASSERT(uncompressed_len, "TNG library: The full length of the uncompressed data must be > 0.");
5043
5044     if(block->id != TNG_TRAJ_POSITIONS &&
5045        block->id != TNG_TRAJ_VELOCITIES)
5046     {
5047         fprintf(stderr, "TNG library: Can only uncompress positions and velocities with the"
5048                "TNG method.\n");
5049         return(TNG_FAILURE);
5050     }
5051     if(type != TNG_FLOAT_DATA && type != TNG_DOUBLE_DATA)
5052     {
5053         fprintf(stderr, "TNG library: Data type not supported.\n");
5054         return(TNG_FAILURE);
5055     }
5056
5057     if(type == TNG_FLOAT_DATA)
5058     {
5059         f_dest = malloc(uncompressed_len);
5060         if(!f_dest)
5061         {
5062             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
5063                 uncompressed_len, __FILE__, __LINE__);
5064             return(TNG_CRITICAL);
5065         }
5066         result = tng_compress_uncompress_float(start_pos, f_dest);
5067     }
5068     else
5069     {
5070         d_dest = malloc(uncompressed_len);
5071         if(!d_dest)
5072         {
5073             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
5074                 uncompressed_len, __FILE__, __LINE__);
5075             return(TNG_CRITICAL);
5076         }
5077         result = tng_compress_uncompress(start_pos, d_dest);
5078     }
5079
5080     if(result == 1)
5081     {
5082         fprintf(stderr, "TNG library: Cannot uncompress TNG compressed block.\n");
5083         return(TNG_FAILURE);
5084     }
5085
5086     offset = (unsigned long)((char *)start_pos - (char *)block->block_contents);
5087
5088     block->block_contents_size = (int64_t)(uncompressed_len + offset);
5089
5090     temp = realloc(block->block_contents, uncompressed_len + offset);
5091     if(!temp)
5092     {
5093         free(block->block_contents);
5094         block->block_contents = 0;
5095         if(d_dest)
5096         {
5097             free(d_dest);
5098         }
5099         if(f_dest)
5100         {
5101             free(f_dest);
5102         }
5103         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5104                block->block_contents_size, __FILE__, __LINE__);
5105         return(TNG_CRITICAL);
5106     }
5107
5108     if(type == TNG_FLOAT_DATA)
5109     {
5110         memcpy(temp + offset, f_dest, uncompressed_len);
5111     }
5112     else
5113     {
5114         memcpy(temp + offset, d_dest, uncompressed_len);
5115     }
5116
5117     block->block_contents = temp;
5118
5119     if(d_dest)
5120     {
5121         free(d_dest);
5122     }
5123     if(f_dest)
5124     {
5125         free(f_dest);
5126     }
5127     return(TNG_SUCCESS);
5128 }
5129
5130 #ifdef USE_ZLIB
5131 static tng_function_status tng_gzip_compress(tng_trajectory_t tng_data,
5132                                              tng_gen_block_t block,
5133                                              void *start_pos, const int len)
5134 {
5135     Bytef *dest;
5136     char *temp;
5137     unsigned long max_len, stat, offset;
5138     (void)tng_data;
5139
5140     max_len = compressBound(len);
5141     dest = malloc(max_len);
5142     if(!dest)
5143     {
5144         fprintf(stderr, "TNG library: Cannot allocate memory (%ld bytes). %s: %d\n",
5145                max_len, __FILE__, __LINE__);
5146         return(TNG_CRITICAL);
5147     }
5148
5149     stat = compress(dest, &max_len, start_pos, len);
5150     if(stat != (unsigned long)Z_OK)
5151     {
5152         free(dest);
5153         if(stat == (unsigned long)Z_MEM_ERROR)
5154         {
5155             fprintf(stderr, "TNG library: Not enough memory. ");
5156         }
5157         else if(stat == (unsigned long)Z_BUF_ERROR)
5158         {
5159             fprintf(stderr, "TNG library: Destination buffer too small. ");
5160         }
5161         fprintf(stderr, "TNG library: Error gzipping data. %s: %d\n", __FILE__, __LINE__);
5162         return(TNG_FAILURE);
5163     }
5164
5165     offset = (char *)start_pos - block->block_contents;
5166
5167     block->block_contents_size = max_len + offset;
5168
5169     temp = realloc(block->block_contents, block->block_contents_size);
5170     if(!temp)
5171     {
5172         free(block->block_contents);
5173         free(dest);
5174         block->block_contents = 0;
5175         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5176                block->block_contents_size, __FILE__, __LINE__);
5177         return(TNG_CRITICAL);
5178     }
5179
5180     block->block_contents = temp;
5181
5182     memcpy(temp + offset, dest, max_len);
5183
5184     free(dest);
5185
5186     return(TNG_SUCCESS);
5187 }
5188
5189 static tng_function_status tng_gzip_uncompress(tng_trajectory_t tng_data,
5190                                                tng_gen_block_t block,
5191                                                void *start_pos,
5192                                                unsigned long uncompressed_len)
5193 {
5194     Bytef *dest;
5195     char *temp;
5196     unsigned long stat;
5197     int offset;
5198     (void)tng_data;
5199
5200     offset = (char *)start_pos - (char *)block->block_contents;
5201
5202     dest = malloc(uncompressed_len);
5203     if(!dest)
5204     {
5205         fprintf(stderr, "TNG library: Cannot allocate memory (%lud bytes). %s: %d\n",
5206                uncompressed_len, __FILE__, __LINE__);
5207         return(TNG_CRITICAL);
5208     }
5209
5210     stat = uncompress(dest, &uncompressed_len, (Bytef *) start_pos,
5211                       block->block_contents_size - offset);
5212
5213     if(stat != Z_OK)
5214     {
5215         free(dest);
5216         if(stat == (unsigned long)Z_MEM_ERROR)
5217         {
5218             fprintf(stderr, "TNG library: Not enough memory. ");
5219         }
5220         else if(stat == (unsigned long)Z_BUF_ERROR)
5221         {
5222             fprintf(stderr, "TNG library: Destination buffer too small. ");
5223         }
5224         else if(stat == (unsigned long)Z_DATA_ERROR)
5225         {
5226             fprintf(stderr, "TNG library: Data corrupt. ");
5227         }
5228         fprintf(stderr, "TNG library: Error uncompressing gzipped data. %s: %d\n", __FILE__,
5229                __LINE__);
5230         return(TNG_FAILURE);
5231     }
5232
5233
5234     block->block_contents_size = uncompressed_len + offset;
5235
5236     temp = realloc(block->block_contents, uncompressed_len + offset);
5237     if(!temp)
5238     {
5239         free(block->block_contents);
5240         block->block_contents = 0;
5241         free(dest);
5242         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5243                block->block_contents_size, __FILE__, __LINE__);
5244         return(TNG_CRITICAL);
5245     }
5246
5247     memcpy(temp + offset, dest, uncompressed_len);
5248
5249     block->block_contents = temp;
5250
5251     free(dest);
5252     return(TNG_SUCCESS);
5253 }
5254 #endif
5255
5256 /** Allocate memory for storing particle data.
5257  * The allocated block will be refered to by data->values.
5258  * @param tng_data is a trajectory data container.
5259  * @param data is the data struct, which will contain the allocated memory in
5260  * data->values.
5261  * @param n_frames is the number of frames of data to store.
5262  * @param n_particles is the number of particles with data.
5263  * @param n_values_per_frame is the number of data values per particle and
5264  * frame.
5265  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5266  * error has occured.
5267  */
5268 static tng_function_status tng_allocate_particle_data_mem
5269                 (tng_trajectory_t tng_data,
5270                  tng_particle_data_t data,
5271                  int64_t n_frames,
5272                  int64_t stride_length,
5273                  const int64_t n_particles,
5274                  const int64_t n_values_per_frame)
5275 {
5276     void ***values;
5277     int64_t i, j, k, size, frame_alloc;
5278     (void)tng_data;
5279
5280     if(n_particles == 0 || n_values_per_frame == 0)
5281     {
5282         return(TNG_FAILURE);
5283     }
5284
5285     if(data->strings && data->datatype == TNG_CHAR_DATA)
5286     {
5287         for(i = 0; i < data->n_frames; i++)
5288         {
5289             for(j = 0; j < n_particles; j++)
5290             {
5291                 for(k = 0; k < data->n_values_per_frame; k++)
5292                 {
5293                     if(data->strings[i][j][k])
5294                     {
5295                         free(data->strings[i][j][k]);
5296                     }
5297                 }
5298                 free(data->strings[i][j]);
5299             }
5300             free(data->strings[i]);
5301         }
5302         free(data->strings);
5303     }
5304     data->n_frames = n_frames;
5305     n_frames = tng_max_i64(1, n_frames);
5306     data->stride_length = tng_max_i64(1, stride_length);
5307     data->n_values_per_frame = n_values_per_frame;
5308     frame_alloc = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
5309
5310     if(data->datatype == TNG_CHAR_DATA)
5311     {
5312         data->strings = malloc(sizeof(char ***) * frame_alloc);
5313         for(i = 0; i < frame_alloc; i++)
5314         {
5315             data->strings[i] = malloc(sizeof(char **) *
5316                                     n_particles);
5317             if(!data->strings[i])
5318             {
5319                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5320                     sizeof(union data_values *) * n_particles,
5321                     __FILE__, __LINE__);
5322                 return(TNG_CRITICAL);
5323             }
5324             for(j = 0; j < n_particles; j++)
5325             {
5326                 data->strings[i][j] = malloc(sizeof(char *) *
5327                                             n_values_per_frame);
5328                 if(!data->strings[i][j])
5329                 {
5330                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5331                         sizeof(union data_values) * n_values_per_frame,
5332                         __FILE__, __LINE__);
5333                     return(TNG_CRITICAL);
5334                 }
5335                 for(k = 0; k < n_values_per_frame; k++)
5336                 {
5337                     data->strings[i][j][k] = 0;
5338                 }
5339             }
5340         }
5341     }
5342     else
5343     {
5344         switch(data->datatype)
5345         {
5346         case TNG_INT_DATA:
5347             size = sizeof(int64_t);
5348             break;
5349         case TNG_FLOAT_DATA:
5350             size = sizeof(float);
5351             break;
5352         case TNG_DOUBLE_DATA:
5353         default:
5354             size = sizeof(double);
5355         }
5356
5357         values = realloc(data->values,
5358                          size * frame_alloc *
5359                          n_particles * n_values_per_frame);
5360         if(!values)
5361         {
5362             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5363                    size * frame_alloc *
5364                    n_particles * n_values_per_frame,
5365                    __FILE__, __LINE__);
5366             free(data->values);
5367             data->values = 0;
5368             return(TNG_CRITICAL);
5369         }
5370         data->values = values;
5371     }
5372     return(TNG_SUCCESS);
5373 }
5374
5375 static tng_function_status tng_particle_data_find
5376                 (tng_trajectory_t tng_data,
5377                  const int64_t id,
5378                  tng_particle_data_t *data)
5379 {
5380     int64_t block_index, i;
5381     tng_trajectory_frame_set_t frame_set = &tng_data->
5382                                            current_trajectory_frame_set;
5383     char block_type_flag;
5384
5385     if(tng_data->current_trajectory_frame_set_input_file_pos > 0 ||
5386        tng_data->current_trajectory_frame_set_output_file_pos > 0)
5387     {
5388         block_type_flag = TNG_TRAJECTORY_BLOCK;
5389     }
5390     else
5391     {
5392         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
5393     }
5394
5395     block_index = -1;
5396     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5397     {
5398         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
5399         {
5400             *data = &frame_set->tr_particle_data[i];
5401             if((*data)->block_id == id)
5402             {
5403                 block_index = i;
5404                 break;
5405             }
5406         }
5407     }
5408     else
5409     {
5410         for(i = 0; i < tng_data->n_particle_data_blocks; i++)
5411         {
5412             *data = &tng_data->non_tr_particle_data[i];
5413             if((*data)->block_id == id)
5414             {
5415                 block_index = i;
5416                 break;
5417             }
5418         }
5419     }
5420     if(block_index == -1)
5421     {
5422         return(TNG_FAILURE);
5423     }
5424     return(TNG_SUCCESS);
5425 }
5426
5427 static tng_function_status tng_data_find
5428                 (tng_trajectory_t tng_data,
5429                  const int64_t id,
5430                  tng_non_particle_data_t *data)
5431 {
5432     int64_t block_index, i;
5433     tng_trajectory_frame_set_t frame_set = &tng_data->
5434                                            current_trajectory_frame_set;
5435     char block_type_flag;
5436
5437     if(tng_data->current_trajectory_frame_set_input_file_pos > 0 ||
5438        tng_data->current_trajectory_frame_set_output_file_pos > 0)
5439     {
5440         block_type_flag = TNG_TRAJECTORY_BLOCK;
5441     }
5442     else
5443     {
5444         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
5445     }
5446
5447     block_index = -1;
5448     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5449     {
5450         for(i = 0; i < frame_set->n_data_blocks; i++)
5451         {
5452             *data = &frame_set->tr_data[i];
5453             if((*data)->block_id == id)
5454             {
5455                 block_index = i;
5456                 break;
5457             }
5458         }
5459         if(block_index == -1)
5460         {
5461             for(i = 0; i < tng_data->n_data_blocks; i++)
5462             {
5463                 *data = &tng_data->non_tr_data[i];
5464                 if((*data)->block_id == id)
5465                 {
5466                     block_index = i;
5467                     break;
5468                 }
5469             }
5470         }
5471     }
5472     else
5473     {
5474         for(i = 0; i < tng_data->n_data_blocks; i++)
5475         {
5476             *data = &tng_data->non_tr_data[i];
5477             if((*data)->block_id == id)
5478             {
5479                 block_index = i;
5480                 break;
5481             }
5482         }
5483     }
5484     if(block_index == -1)
5485     {
5486         return(TNG_FAILURE);
5487     }
5488     return(TNG_SUCCESS);
5489 }
5490
5491 static tng_function_status tng_data_block_len_calculate
5492                 (const tng_trajectory_t tng_data,
5493                  const tng_particle_data_t data,
5494                  const tng_bool is_particle_data,
5495                  const int64_t n_frames,
5496                  const int64_t frame_step,
5497                  const int64_t stride_length,
5498                  const int64_t num_first_particle,
5499                  const int64_t n_particles,
5500                  const char dependency,
5501                  int64_t *data_start_pos,
5502                  int64_t *len)
5503 {
5504     int size;
5505     int64_t i, j, k;
5506     char ***first_dim_values, **second_dim_values;
5507     (void)tng_data;
5508
5509     if(data == 0)
5510     {
5511         return(TNG_SUCCESS);
5512     }
5513
5514     switch(data->datatype)
5515     {
5516     case TNG_CHAR_DATA:
5517         size = 1;
5518         break;
5519     case TNG_INT_DATA:
5520         size = sizeof(int64_t);
5521         break;
5522     case TNG_FLOAT_DATA:
5523         size = sizeof(float);
5524         break;
5525     case TNG_DOUBLE_DATA:
5526     default:
5527         size = sizeof(double);
5528     }
5529
5530     *len = sizeof(char) * 2 + sizeof(data->n_values_per_frame) +
5531            sizeof(data->codec_id);
5532     if(is_particle_data)
5533     {
5534         *len += sizeof(num_first_particle) + sizeof(n_particles);
5535     }
5536
5537     if(stride_length > 1)
5538     {
5539         *len += sizeof(data->first_frame_with_data) +
5540                 sizeof(data->stride_length);
5541     }
5542
5543     if(data->codec_id != TNG_UNCOMPRESSED)
5544     {
5545         *len += sizeof(data->compression_multiplier);
5546     }
5547
5548     if(dependency & TNG_FRAME_DEPENDENT)
5549     {
5550         *len += sizeof(char);
5551     }
5552
5553     *data_start_pos = *len;
5554
5555     if(data->datatype == TNG_CHAR_DATA)
5556     {
5557         if(is_particle_data)
5558         {
5559             for(i = 0; i < n_frames; i++)
5560             {
5561                 first_dim_values = data->strings[i];
5562                 for(j = num_first_particle; j < num_first_particle + n_particles;
5563                     j++)
5564                 {
5565                     second_dim_values = first_dim_values[j];
5566                     for(k = 0; k < data->n_values_per_frame; k++)
5567                     {
5568                         *len += strlen(second_dim_values[k]) + 1;
5569                     }
5570                 }
5571             }
5572         }
5573         else
5574         {
5575             for(i = 0; i < n_frames; i++)
5576             {
5577                 second_dim_values = ((tng_non_particle_data_t)data)->strings[i];
5578                 for(j = 0; j < data->n_values_per_frame; j++)
5579                 {
5580                     *len += strlen(second_dim_values[j]) + 1;
5581                 }
5582             }
5583         }
5584     }
5585     else
5586     {
5587         *len += size * frame_step * n_particles * data->n_values_per_frame;
5588     }
5589
5590     return(TNG_SUCCESS);
5591 }
5592
5593 /** Read the values of a particle data block
5594  * @param tng_data is a trajectory data container.
5595  * @param block is the block to store the data (should already contain
5596  * the block headers and the block contents).
5597  * @param offset is the reading offset to point at the place where the actual
5598  * values are stored, starting from the beginning of the block_contents. The
5599  * offset is changed during the reading.
5600  * @param datatype is the type of data of the data block (char, int, float or
5601  * double).
5602  * @param num_first_particle is the number of the first particle in the data
5603  * block. This should be the same as in the corresponding particle mapping
5604  * block.
5605  * @param n_particles is the number of particles in the data block. This should
5606  * be the same as in the corresponding particle mapping block.
5607  * @param first_frame_with_data is the frame number of the first frame with data
5608  * in this data block.
5609  * @param stride_length is the number of frames between each data entry.
5610  * @param n_frames is the number of frames in this data block.
5611  * @param n_values is the number of values per particle and frame stored in this
5612  * data block.
5613  * @param codec_id is the ID of the codec to compress the data.
5614  * @param multiplier is the multiplication factor applied to each data value
5615  * before compression. This factor is applied since some compression algorithms
5616  * work only on integers.
5617  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5618  * error has occured.
5619  */
5620 static tng_function_status tng_particle_data_read
5621                 (tng_trajectory_t tng_data,
5622                  tng_gen_block_t block,
5623                  int *offset,
5624                  const char datatype,
5625                  const int64_t num_first_particle,
5626                  const int64_t n_particles,
5627                  const int64_t first_frame_with_data,
5628                  const int64_t stride_length,
5629                  int64_t n_frames,
5630                  const int64_t n_values,
5631                  const int64_t codec_id,
5632                  const double multiplier)
5633 {
5634     int64_t i, j, k, tot_n_particles, n_frames_div;
5635     int size, len;
5636     unsigned long data_size;
5637     char ***first_dim_values, **second_dim_values;
5638     tng_particle_data_t data;
5639     tng_trajectory_frame_set_t frame_set =
5640     &tng_data->current_trajectory_frame_set;
5641     char block_type_flag;
5642
5643     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
5644
5645     switch(datatype)
5646     {
5647     case TNG_CHAR_DATA:
5648         size = 1;
5649         break;
5650     case TNG_INT_DATA:
5651         size = sizeof(int64_t);
5652         break;
5653     case TNG_FLOAT_DATA:
5654         size = sizeof(float);
5655         break;
5656     case TNG_DOUBLE_DATA:
5657     default:
5658         size = sizeof(double);
5659     }
5660
5661     /* If the block does not exist, create it */
5662     if(tng_particle_data_find(tng_data, block->id, &data) != TNG_SUCCESS)
5663     {
5664         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
5665         {
5666             block_type_flag = TNG_TRAJECTORY_BLOCK;
5667         }
5668         else
5669         {
5670             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
5671         }
5672
5673         if(tng_particle_data_block_create(tng_data, block_type_flag) !=
5674            TNG_SUCCESS)
5675         {
5676             fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n",
5677                    __FILE__, __LINE__);
5678             return(TNG_CRITICAL);
5679         }
5680         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5681         {
5682             data = &frame_set->tr_particle_data[frame_set->
5683                                                 n_particle_data_blocks - 1];
5684         }
5685         else
5686         {
5687             data = &tng_data->non_tr_particle_data[tng_data->
5688                                                    n_particle_data_blocks - 1];
5689         }
5690         data->block_id = block->id;
5691
5692         data->block_name = malloc(strlen(block->name) + 1);
5693         if(!data->block_name)
5694         {
5695             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
5696                    (int)strlen(block->name)+1, __FILE__, __LINE__);
5697             return(TNG_CRITICAL);
5698         }
5699         strcpy(data->block_name, block->name);
5700
5701         data->datatype = datatype;
5702
5703         data->values = 0;
5704         /* FIXME: Memory leak from strings. */
5705         data->strings = 0;
5706         data->n_frames = 0;
5707         data->codec_id = codec_id;
5708         data->compression_multiplier = multiplier;
5709         data->last_retrieved_frame = -1;
5710     }
5711
5712     if(/*block_type_flag == TNG_TRAJECTORY_BLOCK &&*/
5713        tng_data->current_trajectory_frame_set_input_file_pos > 0 &&
5714        tng_data->var_num_atoms_flag)
5715     {
5716         tot_n_particles = frame_set->n_particles;
5717     }
5718     else
5719     {
5720         tot_n_particles = tng_data->n_particles;
5721     }
5722
5723     n_frames_div = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
5724
5725     if(codec_id != TNG_UNCOMPRESSED)
5726     {
5727         data_size = (unsigned long)(n_frames_div * size * n_particles * n_values);
5728         switch(codec_id)
5729         {
5730         case TNG_XTC_COMPRESSION:
5731             fprintf(stderr, "TNG library: XTC compression not implemented yet.\n");
5732             break;
5733         case TNG_TNG_COMPRESSION:
5734 /*            fprintf(stderr, "TNG library: Before TNG uncompression: %"PRId64"\n", block->block_contents_size);*/
5735             if(tng_uncompress(tng_data, block, datatype,
5736                               block->block_contents + *offset,
5737                               data_size) != TNG_SUCCESS)
5738             {
5739                 fprintf(stderr, "TNG library: Could not read tng compressed block data. %s: %d\n",
5740                        __FILE__, __LINE__);
5741                 return(TNG_CRITICAL);
5742             }
5743 /*            fprintf(stderr, "TNG library: After TNG uncompression: %"PRId64"\n", block->block_contents_size);*/
5744             break;
5745 #ifdef USE_ZLIB
5746         case TNG_GZIP_COMPRESSION:
5747 /*            fprintf(stderr, "TNG library: Before GZIP uncompression: %"PRId64"\n", block->block_contents_size);*/
5748             if(tng_gzip_uncompress(tng_data, block,
5749                                    block->block_contents + *offset,
5750                                    data_size) != TNG_SUCCESS)
5751             {
5752                 fprintf(stderr, "TNG library: Could not read gzipped block data. %s: %d\n", __FILE__,
5753                     __LINE__);
5754                 return(TNG_CRITICAL);
5755             }
5756 /*            fprintf(stderr, "TNG library: After GZIP uncompression: %"PRId64"\n", block->block_contents_size);*/
5757             break;
5758 #endif
5759         }
5760     }
5761     /* Allocate memory */
5762     if(!data->values || data->n_frames != n_frames ||
5763        data->n_values_per_frame != n_values)
5764     {
5765         if(tng_allocate_particle_data_mem(tng_data, data, n_frames,
5766                                           stride_length,
5767                                           tot_n_particles, n_values) !=
5768            TNG_SUCCESS)
5769         {
5770             fprintf(stderr, "TNG library: Cannot allocate memory for particle data. %s: %d\n",
5771                    __FILE__, __LINE__);
5772             return(TNG_CRITICAL);
5773         }
5774     }
5775
5776     data->first_frame_with_data = first_frame_with_data;
5777
5778     if(datatype == TNG_CHAR_DATA)
5779     {
5780         for(i = 0; i < n_frames_div; i++)
5781         {
5782             first_dim_values = data->strings[i];
5783             for(j = num_first_particle; j < num_first_particle + n_particles;
5784                 j++)
5785             {
5786                 second_dim_values = first_dim_values[j];
5787                 for(k = 0; k < n_values; k++)
5788                 {
5789                     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
5790                               TNG_MAX_STR_LEN);
5791                     if(second_dim_values[k])
5792                     {
5793                         free(second_dim_values[k]);
5794                     }
5795                     second_dim_values[k] = malloc(len);
5796                     if(!second_dim_values[k])
5797                     {
5798                         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
5799                             len, __FILE__, __LINE__);
5800                         return(TNG_CRITICAL);
5801                     }
5802                     strncpy(second_dim_values[k],
5803                             block->block_contents+*offset, len);
5804                     *offset += len;
5805                 }
5806             }
5807         }
5808     }
5809     else
5810     {
5811         memcpy((char *)data->values + n_frames_div * size * n_values *
5812                num_first_particle,
5813                block->block_contents + *offset,
5814                block->block_contents_size - *offset);
5815         switch(datatype)
5816         {
5817         case TNG_FLOAT_DATA:
5818             if(tng_data->input_endianness_swap_func_32)
5819             {
5820                 for(i = 0; i < (block->block_contents_size - *offset); i+=size)
5821                 {
5822                     if(tng_data->input_endianness_swap_func_32(tng_data,
5823                         (int32_t *)((char *)data->values + i))
5824                         != TNG_SUCCESS)
5825                     {
5826                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5827                                 __FILE__, __LINE__);
5828                     }
5829                 }
5830             }
5831             break;
5832         case TNG_INT_DATA:
5833         case TNG_DOUBLE_DATA:
5834             if(tng_data->input_endianness_swap_func_64)
5835             {
5836                 for(i = 0; i < (block->block_contents_size - *offset); i+=size)
5837                 {
5838                     if(tng_data->input_endianness_swap_func_64(tng_data,
5839                         (int64_t *)((char *)data->values + i))
5840                         != TNG_SUCCESS)
5841                     {
5842                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5843                                 __FILE__, __LINE__);
5844                     }
5845                 }
5846             }
5847             break;
5848         case TNG_CHAR_DATA:
5849             break;
5850         }
5851     }
5852     return(TNG_SUCCESS);
5853 }
5854
5855 /** Write a particle data block
5856  * @param tng_data is a trajectory data container.
5857  * @param block is the block to store the data (should already contain
5858  * the block headers and the block contents).
5859  * @param block_index is the index number of the data block in the frame set.
5860  * @param mapping is the particle mapping that is relevant for the data block.
5861  * @param hash_mode is an option to decide whether to use the md5 hash or not.
5862  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
5863  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5864  * error has occured.
5865  */
5866 static tng_function_status tng_particle_data_block_write
5867                 (tng_trajectory_t tng_data,
5868                  tng_gen_block_t block,
5869                  const int64_t block_index,
5870                  const tng_particle_mapping_t mapping,
5871                  const char hash_mode)
5872 {
5873     int64_t n_particles, num_first_particle, n_frames, stride_length;
5874     int64_t frame_step, data_start_pos;
5875     int64_t i, j, k;
5876     int size;
5877     size_t len, offset = 0;
5878     char dependency, temp, *temp_name;
5879     double multiplier;
5880     char ***first_dim_values, **second_dim_values;
5881     tng_trajectory_frame_set_t frame_set;
5882     tng_function_status stat;
5883
5884     tng_particle_data_t data;
5885     char block_type_flag;
5886
5887     frame_set = &tng_data->current_trajectory_frame_set;
5888
5889     /* If we have already started writing frame sets it is too late to write
5890      * non-trajectory data blocks */
5891     if(tng_data->current_trajectory_frame_set_output_file_pos > 0)
5892     {
5893         block_type_flag = TNG_TRAJECTORY_BLOCK;
5894     }
5895     else
5896     {
5897         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
5898     }
5899
5900     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
5901     {
5902         return(TNG_CRITICAL);
5903     }
5904
5905     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5906     {
5907         data = &frame_set->tr_particle_data[block_index];
5908
5909         /* If this data block has not had any data added in this frame set
5910          * do not write it. */
5911         if(data->first_frame_with_data < frame_set->first_frame)
5912         {
5913             return(TNG_SUCCESS);
5914         }
5915
5916         stride_length = tng_max_i64(1, data->stride_length);
5917     }
5918     else
5919     {
5920         data = &tng_data->non_tr_particle_data[block_index];
5921         stride_length = 1;
5922     }
5923
5924     switch(data->datatype)
5925     {
5926     case TNG_CHAR_DATA:
5927         size = 1;
5928         break;
5929     case TNG_INT_DATA:
5930         size = sizeof(int64_t);
5931         break;
5932     case TNG_FLOAT_DATA:
5933         size = sizeof(float);
5934         break;
5935     case TNG_DOUBLE_DATA:
5936     default:
5937         size = sizeof(double);
5938     }
5939
5940     len = strlen(data->block_name) + 1;
5941
5942     if(!block->name || strlen(block->name) < len)
5943     {
5944         temp_name = realloc(block->name, len);
5945         if(!temp_name)
5946         {
5947             fprintf(stderr, "TNG library: Cannot allocate memory (%lud bytes). %s: %d\n", len,
5948                    __FILE__, __LINE__);
5949             free(block->name);
5950             block->name = 0;
5951             return(TNG_CRITICAL);
5952         }
5953         block->name = temp_name;
5954     }
5955     strncpy(block->name, data->block_name, len);
5956     block->id = data->block_id;
5957
5958     /* If writing frame independent data data->n_frames is 0, but n_frames
5959        is used for the loop writing the data (and reserving memory) and needs
5960        to be at least 1 */
5961     n_frames = tng_max_i64(1, data->n_frames);
5962
5963     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5964     {
5965         /* If the frame set is finished before writing the full number of frames
5966            make sure the data block is not longer than the frame set. */
5967         n_frames = tng_min_i64(n_frames, frame_set->n_frames);
5968
5969         n_frames -= (data->first_frame_with_data - frame_set->first_frame);
5970     }
5971
5972     frame_step = (n_frames % stride_length) ? n_frames / stride_length + 1:
5973                  n_frames / stride_length;
5974
5975     /* TNG compression will use compression precision to get integers from
5976      * floating point data. The compression multiplier stores that information
5977      * to be able to return the precision of the compressed data. */
5978     if(data->codec_id == TNG_TNG_COMPRESSION)
5979     {
5980         data->compression_multiplier = tng_data->compression_precision;
5981     }
5982     /* Uncompressed data blocks do not use compression multipliers at all.
5983      * GZip compression does not need it either. */
5984     else if(data->codec_id == TNG_UNCOMPRESSED || data->codec_id == TNG_GZIP_COMPRESSION)
5985     {
5986         data->compression_multiplier = 1.0;
5987     }
5988
5989     if(mapping && mapping->n_particles != 0)
5990     {
5991         n_particles = mapping->n_particles;
5992         num_first_particle = mapping->num_first_particle;
5993     }
5994     else
5995     {
5996         num_first_particle = 0;
5997         if(tng_data->var_num_atoms_flag)
5998         {
5999             n_particles = frame_set->n_particles;
6000         }
6001         else
6002         {
6003             n_particles = tng_data->n_particles;
6004         }
6005     }
6006
6007     if(block_type_flag == TNG_TRAJECTORY_BLOCK && data->n_frames > 0)
6008     {
6009         dependency = TNG_FRAME_DEPENDENT + TNG_PARTICLE_DEPENDENT;
6010     }
6011     else
6012     {
6013         dependency = TNG_PARTICLE_DEPENDENT;
6014     }
6015
6016     if(tng_data_block_len_calculate(tng_data, data, TNG_TRUE, n_frames,
6017                                     frame_step, stride_length, num_first_particle,
6018                                     n_particles, dependency, &data_start_pos,
6019                                     &block->block_contents_size) != TNG_SUCCESS)
6020     {
6021         fprintf(stderr, "TNG library: Cannot calculate length of particle data block. %s: %d\n",
6022                 __FILE__, __LINE__);
6023         return(TNG_CRITICAL);
6024     }
6025
6026     if(block->block_contents)
6027     {
6028         free(block->block_contents);
6029     }
6030     block->block_contents = malloc(block->block_contents_size);
6031     if(!block->block_contents)
6032     {
6033         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
6034                block->block_contents_size, __FILE__, __LINE__);
6035         return(TNG_CRITICAL);
6036     }
6037
6038
6039     memcpy(block->block_contents, &data->datatype, sizeof(char));
6040     offset += sizeof(char);
6041
6042     memcpy(block->block_contents+offset, &dependency, sizeof(char));
6043     offset += sizeof(char);
6044
6045     if(dependency & TNG_FRAME_DEPENDENT)
6046     {
6047         if(stride_length > 1)
6048         {
6049             temp = 1;
6050         }
6051         else
6052         {
6053             temp = 0;
6054         }
6055         memcpy(block->block_contents+offset, &temp, sizeof(char));
6056         offset += sizeof(char);
6057     }
6058
6059     memcpy(block->block_contents+offset, &data->n_values_per_frame,
6060            sizeof(data->n_values_per_frame));
6061     if(tng_data->output_endianness_swap_func_64)
6062     {
6063         if(tng_data->output_endianness_swap_func_64(tng_data,
6064            (int64_t *)block->header_contents+offset)
6065             != TNG_SUCCESS)
6066         {
6067             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6068                     __FILE__, __LINE__);
6069         }
6070     }
6071     offset += sizeof(data->n_values_per_frame);
6072
6073     memcpy(block->block_contents+offset, &data->codec_id,
6074            sizeof(data->codec_id));
6075     if(tng_data->output_endianness_swap_func_64)
6076     {
6077         if(tng_data->output_endianness_swap_func_64(tng_data,
6078            (int64_t *)block->header_contents+offset)
6079             != TNG_SUCCESS)
6080         {
6081             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6082                     __FILE__, __LINE__);
6083         }
6084     }
6085     offset += sizeof(data->codec_id);
6086
6087     if(data->codec_id != TNG_UNCOMPRESSED)
6088     {
6089         memcpy(block->block_contents+offset, &data->compression_multiplier,
6090                sizeof(data->compression_multiplier));
6091         if(tng_data->output_endianness_swap_func_64)
6092         {
6093             if(tng_data->output_endianness_swap_func_64(tng_data,
6094                (int64_t *)block->header_contents+offset)
6095                 != TNG_SUCCESS)
6096             {
6097                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6098                         __FILE__, __LINE__);
6099             }
6100         }
6101         offset += sizeof(data->compression_multiplier);
6102     }
6103
6104     if(data->n_frames > 0 && stride_length > 1)
6105     {
6106         /* FIXME: first_frame_with_data is not reliably set */
6107         if(data->first_frame_with_data == 0)
6108         {
6109             data->first_frame_with_data = frame_set->first_frame;
6110         }
6111         memcpy(block->block_contents+offset, &data->first_frame_with_data,
6112                sizeof(data->first_frame_with_data));
6113         if(tng_data->output_endianness_swap_func_64)
6114         {
6115             if(tng_data->output_endianness_swap_func_64(tng_data,
6116                (int64_t *)block->header_contents+offset)
6117                 != TNG_SUCCESS)
6118             {
6119                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6120                         __FILE__, __LINE__);
6121             }
6122         }
6123         offset += sizeof(data->first_frame_with_data);
6124
6125         memcpy(block->block_contents+offset, &stride_length,
6126                sizeof(stride_length));
6127         if(tng_data->output_endianness_swap_func_64)
6128         {
6129             if(tng_data->output_endianness_swap_func_64(tng_data,
6130                (int64_t *)block->header_contents+offset)
6131                 != TNG_SUCCESS)
6132             {
6133                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6134                         __FILE__, __LINE__);
6135             }
6136         }
6137         offset += sizeof(stride_length);
6138     }
6139
6140
6141     memcpy(block->block_contents+offset, &num_first_particle,
6142            sizeof(num_first_particle));
6143     if(tng_data->output_endianness_swap_func_64)
6144     {
6145         if(tng_data->output_endianness_swap_func_64(tng_data,
6146            (int64_t *)block->header_contents+offset)
6147             != TNG_SUCCESS)
6148         {
6149             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6150                     __FILE__, __LINE__);
6151         }
6152     }
6153     offset += sizeof(num_first_particle);
6154
6155     memcpy(block->block_contents+offset, &n_particles, sizeof(n_particles));
6156     if(tng_data->output_endianness_swap_func_64)
6157     {
6158         if(tng_data->output_endianness_swap_func_64(tng_data,
6159            (int64_t *)block->header_contents+offset)
6160             != TNG_SUCCESS)
6161         {
6162             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6163                     __FILE__, __LINE__);
6164         }
6165     }
6166     offset += sizeof(n_particles);
6167
6168     if(data->datatype == TNG_CHAR_DATA)
6169     {
6170         if(data->strings)
6171         {
6172             for(i = 0; i < frame_step; i++)
6173             {
6174                 first_dim_values = data->strings[i];
6175                 for(j = num_first_particle; j < num_first_particle + n_particles;
6176                     j++)
6177                 {
6178                     second_dim_values = first_dim_values[j];
6179                     for(k = 0; k < data->n_values_per_frame; k++)
6180                     {
6181                         len = (unsigned int)strlen(second_dim_values[k]) + 1;
6182                         strncpy(block->block_contents+offset,
6183                                 second_dim_values[k], len);
6184                         offset += len;
6185                     }
6186                 }
6187             }
6188         }
6189     }
6190     else if(data->values)
6191     {
6192         memcpy(block->block_contents + offset, data->values,
6193                block->block_contents_size - offset);
6194
6195         switch(data->datatype)
6196         {
6197         case TNG_FLOAT_DATA:
6198             if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
6199                data->codec_id == TNG_TNG_COMPRESSION)
6200             {
6201                 if(tng_data->input_endianness_swap_func_32)
6202                 {
6203                     for(i = offset; i < block->block_contents_size; i+=size)
6204                     {
6205                         if(tng_data->input_endianness_swap_func_32(tng_data,
6206                            (int32_t *)(block->block_contents + i))
6207                            != TNG_SUCCESS)
6208                         {
6209                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6210                                     __FILE__, __LINE__);
6211                         }
6212                     }
6213                 }
6214             }
6215             else
6216             {
6217                 multiplier = data->compression_multiplier;
6218                 if(fabs(multiplier - 1.0) > 0.00001 ||
6219                    tng_data->input_endianness_swap_func_32)
6220                 {
6221                     for(i = offset; i < block->block_contents_size; i+=size)
6222                     {
6223                         *(float *)(block->block_contents + i) *= (float)multiplier;
6224                         if(tng_data->input_endianness_swap_func_32 &&
6225                         tng_data->input_endianness_swap_func_32(tng_data,
6226                         (int32_t *)(block->block_contents + i))
6227                         != TNG_SUCCESS)
6228                         {
6229                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6230                                     __FILE__, __LINE__);
6231                         }
6232                     }
6233                 }
6234             }
6235             break;
6236         case TNG_INT_DATA:
6237             if(tng_data->input_endianness_swap_func_64)
6238             {
6239                 for(i = offset; i < block->block_contents_size; i+=size)
6240                 {
6241                     if(tng_data->input_endianness_swap_func_64(tng_data,
6242                        (int64_t *)(block->block_contents + i))
6243                        != TNG_SUCCESS)
6244                     {
6245                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6246                                 __FILE__, __LINE__);
6247                     }
6248                 }
6249             }
6250             break;
6251         case TNG_DOUBLE_DATA:
6252             if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
6253                data->codec_id == TNG_TNG_COMPRESSION)
6254             {
6255                 if(tng_data->input_endianness_swap_func_64)
6256                 {
6257                     for(i = offset; i < block->block_contents_size; i+=size)
6258                     {
6259                         if(tng_data->input_endianness_swap_func_64(tng_data,
6260                            (int64_t *)(block->block_contents + i))
6261                            != TNG_SUCCESS)
6262                         {
6263                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6264                                     __FILE__, __LINE__);
6265                         }
6266                     }
6267                 }
6268             }
6269             else
6270             {
6271                 multiplier = data->compression_multiplier;
6272                 if(fabs(multiplier - 1.0) > 0.00001 ||
6273                    tng_data->input_endianness_swap_func_64)
6274                 {
6275                     for(i = offset; i < block->block_contents_size; i+=size)
6276                     {
6277                         *(double *)(block->block_contents + i) *= multiplier;
6278                         if(tng_data->input_endianness_swap_func_64 &&
6279                         tng_data->input_endianness_swap_func_64(tng_data,
6280                         (int64_t *)(block->block_contents + i))
6281                         != TNG_SUCCESS)
6282                         {
6283                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6284                                     __FILE__, __LINE__);
6285                         }
6286                     }
6287                 }
6288             }
6289             break;
6290         case TNG_CHAR_DATA:
6291             break;
6292         }
6293     }
6294     else
6295     {
6296         memset(block->block_contents+offset, 0, block->block_contents_size - offset);
6297     }
6298
6299     frame_set->n_written_frames += frame_set->n_unwritten_frames;
6300     frame_set->n_unwritten_frames = 0;
6301
6302     if(block_type_flag == TNG_NON_TRAJECTORY_BLOCK || frame_set->n_written_frames > 0)
6303     {
6304         switch(data->codec_id)
6305         {
6306         case TNG_XTC_COMPRESSION:
6307             fprintf(stderr, "TNG library: XTC compression not implemented yet.\n");
6308             data->codec_id = TNG_UNCOMPRESSED;
6309             break;
6310         case TNG_TNG_COMPRESSION:
6311             stat = tng_compress(tng_data, block, frame_step,
6312                                 n_particles, data->datatype,
6313                                 block->block_contents + data_start_pos);
6314             if(stat != TNG_SUCCESS)
6315             {
6316                 fprintf(stderr, "TNG library: Could not write tng compressed block data. %s: %d\n",
6317                     __FILE__, __LINE__);
6318                 if(stat == TNG_CRITICAL)
6319                 {
6320                     return(TNG_CRITICAL);
6321                 }
6322                 /* Set the data again, but with no compression (to write only
6323                  * the relevant data) */
6324                 data->codec_id = TNG_UNCOMPRESSED;
6325                 stat = tng_particle_data_block_write(tng_data, block,
6326                                                      block_index, mapping,
6327                                                      hash_mode);
6328                 return(stat);
6329             }
6330             break;
6331 #ifdef USE_ZLIB
6332         case TNG_GZIP_COMPRESSION:
6333     /*         fprintf(stderr, "TNG library: Before compression: %"PRId64"\n", block->block_contents_size);*/
6334             stat = tng_gzip_compress(tng_data, block,
6335                                      block->block_contents + data_start_pos,
6336                                      block->block_contents_size - data_start_pos);
6337             if(stat != TNG_SUCCESS)
6338             {
6339                 fprintf(stderr, "TNG library: Could not write gzipped block data. %s: %d\n", __FILE__,
6340                     __LINE__);
6341                 if(stat == TNG_CRITICAL)
6342                 {
6343                     return(TNG_CRITICAL);
6344                 }
6345                 /* Set the data again, but with no compression (to write only
6346                  * the relevant data) */
6347                 data->codec_id = TNG_UNCOMPRESSED;
6348                 stat = tng_particle_data_block_write(tng_data, block,
6349                                                      block_index, mapping,
6350                                                      hash_mode);
6351                 return(stat);
6352             }
6353     /*         fprintf(stderr, "TNG library: After compression: %"PRId64"\n", block->block_contents_size);*/
6354             break;
6355 #endif
6356         }
6357     }
6358
6359     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
6360     {
6361         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
6362                tng_data->output_file_path, __FILE__, __LINE__);
6363         return(TNG_CRITICAL);
6364     }
6365
6366     if(fwrite(block->block_contents, block->block_contents_size, 1,
6367         tng_data->output_file) != 1)
6368     {
6369         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__,
6370                 __LINE__);
6371         return(TNG_CRITICAL);
6372     }
6373
6374     return(TNG_SUCCESS);
6375 }
6376
6377 /* TEST: */
6378 /** Create a non-particle data block
6379  * @param tng_data is a trajectory data container.
6380  * @param block_type_flag specifies if this is a trajectory block or a
6381  * non-trajectory block. (TNG_TRAJECTORY_BLOCK or TNG_NON_TRAJECTORY_BLOCK)
6382  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6383  * error has occured.
6384  */
6385 static tng_function_status tng_data_block_create
6386                 (tng_trajectory_t tng_data,
6387                  const char block_type_flag)
6388 {
6389     tng_trajectory_frame_set_t frame_set =
6390     &tng_data->current_trajectory_frame_set;
6391
6392     tng_non_particle_data_t data;
6393
6394     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
6395     {
6396         frame_set->n_data_blocks++;
6397         data = realloc(frame_set->tr_data, sizeof(struct tng_non_particle_data) *
6398                        frame_set->n_data_blocks);
6399         if(!data)
6400         {
6401             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
6402                 sizeof(struct tng_non_particle_data) * frame_set->n_data_blocks,
6403                 __FILE__, __LINE__);
6404             free(frame_set->tr_data);
6405             frame_set->tr_data = 0;
6406             return(TNG_CRITICAL);
6407         }
6408         frame_set->tr_data = data;
6409     }
6410     else
6411     {
6412         tng_data->n_data_blocks++;
6413         data = realloc(tng_data->non_tr_data, sizeof(struct tng_non_particle_data) *
6414                         tng_data->n_data_blocks);
6415         if(!data)
6416         {
6417             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
6418                 sizeof(struct tng_non_particle_data) * tng_data->n_data_blocks,
6419                 __FILE__, __LINE__);
6420             free(tng_data->non_tr_data);
6421             tng_data->non_tr_data = 0;
6422             return(TNG_CRITICAL);
6423         }
6424         tng_data->non_tr_data = data;
6425     }
6426
6427     return(TNG_SUCCESS);
6428 }
6429
6430 /* TEST: */
6431 /** Allocate memory for storing non-particle data.
6432  * The allocated block will be refered to by data->values.
6433  * @param tng_data is a trajectory data container.
6434  * @param data is the data struct, which will contain the allocated memory in
6435  * data->values.
6436  * @param n_frames is the number of frames of data to store.
6437  * @param n_values_per_frame is the number of data values per frame.
6438  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6439  * error has occured.
6440  */
6441 static tng_function_status tng_allocate_data_mem
6442                 (tng_trajectory_t tng_data,
6443                  tng_non_particle_data_t data,
6444                  int64_t n_frames,
6445                  int64_t stride_length,
6446                  const int64_t n_values_per_frame)
6447 {
6448     void **values;
6449     int64_t i, j, size, frame_alloc;
6450     (void)tng_data;
6451
6452     if(n_values_per_frame == 0)
6453     {
6454         return(TNG_FAILURE);
6455     }
6456
6457     if(data->strings && data->datatype == TNG_CHAR_DATA)
6458     {
6459         for(i = 0; i < data->n_frames; i++)
6460         {
6461             for(j = 0; j < data->n_values_per_frame; j++)
6462             {
6463                 if(data->strings[i][j])
6464                 {
6465                     free(data->strings[i][j]);
6466                     data->strings[i][j] = 0;
6467                 }
6468             }
6469             free(data->strings[i]);
6470             data->strings[i] = 0;
6471         }
6472         free(data->strings);
6473     }
6474     data->n_frames = n_frames;
6475     data->stride_length = tng_max_i64(1, stride_length);
6476     n_frames = tng_max_i64(1, n_frames);
6477     data->n_values_per_frame = n_values_per_frame;
6478     frame_alloc = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
6479
6480     if(data->datatype == TNG_CHAR_DATA)
6481     {
6482         data->strings = malloc(sizeof(char **) * frame_alloc);
6483         for(i = 0; i < frame_alloc; i++)
6484         {
6485             data->strings[i] = malloc(sizeof(char *) * n_values_per_frame);
6486             if(!data->strings[i])
6487             {
6488                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
6489                        n_values_per_frame,
6490                        __FILE__, __LINE__);
6491                 return(TNG_CRITICAL);
6492             }
6493             for(j = 0; j < n_values_per_frame; j++)
6494             {
6495                 data->strings[i][j] = 0;
6496             }
6497         }
6498     }
6499     else
6500     {
6501         switch(data->datatype)
6502         {
6503         case TNG_INT_DATA:
6504             size = sizeof(int64_t);
6505             break;
6506         case TNG_FLOAT_DATA:
6507             size = sizeof(float);
6508             break;
6509         case TNG_DOUBLE_DATA:
6510         default:
6511             size = sizeof(double);
6512         }
6513
6514         values = realloc(data->values,
6515                          size * frame_alloc *
6516                          n_values_per_frame);
6517         if(!values)
6518         {
6519             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
6520                    size * frame_alloc *
6521                    n_values_per_frame,
6522                    __FILE__, __LINE__);
6523             free(data->values);
6524             data->values = 0;
6525             return(TNG_CRITICAL);
6526         }
6527         data->values = values;
6528     }
6529
6530     return(TNG_SUCCESS);
6531 }
6532
6533 /** Read the values of a non-particle data block
6534  * @param tng_data is a trajectory data container.
6535  * @param block is the block to store the data (should already contain
6536  * the block headers and the block contents).
6537  * @param offset is the reading offset to point at the place where the actual
6538  * values are stored, starting from the beginning of the block_contents. The
6539  * offset is changed during the reading.
6540  * @param datatype is the type of data of the data block (char, int, float or
6541  * double).
6542  * @param first_frame_with_data is the frame number of the first frame with data
6543  * in this data block.
6544  * @param stride_length is the number of frames between each data entry.
6545  * @param n_frames is the number of frames in this data block.
6546  * @param n_values is the number of values per frame stored in this data block.
6547  * @param codec_id is the ID of the codec to compress the data.
6548  * @param multiplier is the multiplication factor applied to each data value
6549  * before compression. This factor is applied since some compression algorithms
6550  * work only on integers.
6551  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6552  * error has occured.
6553  */
6554 static tng_function_status tng_data_read(tng_trajectory_t tng_data,
6555                                          tng_gen_block_t block,
6556                                          int *offset,
6557                                          const char datatype,
6558                                          const int64_t first_frame_with_data,
6559                                          const int64_t stride_length,
6560                                          int64_t n_frames,
6561                                          const int64_t n_values,
6562                                          const int64_t codec_id,
6563                                          const double multiplier)
6564 {
6565     int64_t i, j, n_frames_div;
6566     int size, len;
6567 #ifdef USE_ZLIB
6568     unsigned long data_size;
6569 #endif
6570     tng_non_particle_data_t data;
6571     tng_trajectory_frame_set_t frame_set =
6572     &tng_data->current_trajectory_frame_set;
6573     char block_type_flag;
6574
6575     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
6576
6577 /*     fprintf(stderr, "TNG library: %s\n", block->name);*/
6578
6579     switch(datatype)
6580     {
6581     case TNG_CHAR_DATA:
6582         size = 1;
6583         break;
6584     case TNG_INT_DATA:
6585         size = sizeof(int64_t);
6586         break;
6587     case TNG_FLOAT_DATA:
6588         size = sizeof(float);
6589         break;
6590     case TNG_DOUBLE_DATA:
6591     default:
6592         size = sizeof(double);
6593     }
6594
6595     /* If the block does not exist, create it */
6596     if(tng_data_find(tng_data, block->id, &data) != TNG_SUCCESS)
6597     {
6598         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
6599         {
6600             block_type_flag = TNG_TRAJECTORY_BLOCK;
6601         }
6602         else
6603         {
6604             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
6605         }
6606
6607         if(tng_data_block_create(tng_data, block_type_flag) !=
6608             TNG_SUCCESS)
6609         {
6610             fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n",
6611                    __FILE__, __LINE__);
6612             return(TNG_CRITICAL);
6613         }
6614         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
6615         {
6616             data = &frame_set->tr_data[frame_set->n_data_blocks - 1];
6617         }
6618         else
6619         {
6620             data = &tng_data->non_tr_data[tng_data->n_data_blocks - 1];
6621         }
6622         data->block_id = block->id;
6623
6624         data->block_name = malloc(strlen(block->name) + 1);
6625         if(!data->block_name)
6626         {
6627             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
6628                    (int)strlen(block->name)+1, __FILE__, __LINE__);
6629             return(TNG_CRITICAL);
6630         }
6631         strcpy(data->block_name, block->name);
6632
6633         data->datatype = datatype;
6634
6635         data->values = 0;
6636         /* FIXME: Memory leak from strings. */
6637         data->strings = 0;
6638         data->n_frames = 0;
6639         data->codec_id = codec_id;
6640         data->compression_multiplier = multiplier;
6641         data->last_retrieved_frame = -1;
6642     }
6643
6644     n_frames_div = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
6645
6646     if(codec_id != TNG_UNCOMPRESSED)
6647     {
6648         switch(codec_id)
6649         {
6650 #ifdef USE_ZLIB
6651         case TNG_GZIP_COMPRESSION:
6652             data_size = n_frames_div * size * n_values;
6653     /*         fprintf(stderr, "TNG library: Before compression: %"PRId64"\n", block->block_contents_size); */
6654             if(tng_gzip_uncompress(tng_data, block,
6655                                    block->block_contents + *offset,
6656                                    data_size) != TNG_SUCCESS)
6657             {
6658                 fprintf(stderr, "TNG library: Could not read gzipped block data. %s: %d\n", __FILE__,
6659                     __LINE__);
6660                 return(TNG_CRITICAL);
6661             }
6662     /*         fprintf(stderr, "TNG library: After compression: %"PRId64"\n", block->block_contents_size); */
6663             break;
6664 #endif
6665         }
6666     }
6667
6668     /* Allocate memory */
6669     if(!data->values || data->n_frames != n_frames ||
6670        data->n_values_per_frame != n_values)
6671     {
6672         if(tng_allocate_data_mem(tng_data, data, n_frames, stride_length,
6673                                  n_values) !=
6674            TNG_SUCCESS)
6675         {
6676             fprintf(stderr, "TNG library: Cannot allocate memory for data. %s: %d\n",
6677                    __FILE__, __LINE__);
6678             return(TNG_CRITICAL);
6679         }
6680     }
6681
6682     data->first_frame_with_data = first_frame_with_data;
6683
6684     if(datatype == TNG_CHAR_DATA)
6685     {
6686         for(i = 0; i < n_frames_div; i++)
6687         {
6688             for(j = 0; j < n_values; j++)
6689             {
6690                 len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
6691                               TNG_MAX_STR_LEN);
6692                 if(data->strings[i][j])
6693                 {
6694                     free(data->strings[i][j]);
6695                 }
6696                 data->strings[i][j] = malloc(len);
6697                 if(!data->strings[i][j])
6698                 {
6699                     fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
6700                            len, __FILE__, __LINE__);
6701                     return(TNG_CRITICAL);
6702                 }
6703                 strncpy(data->strings[i][j], block->block_contents+*offset,
6704                         len);
6705                 *offset += len;
6706             }
6707         }
6708     }
6709     else
6710     {
6711         memcpy(data->values, block->block_contents + *offset,
6712                block->block_contents_size - *offset);
6713         switch(datatype)
6714         {
6715         case TNG_FLOAT_DATA:
6716             if(tng_data->input_endianness_swap_func_32)
6717             {
6718                 for(i = 0; i < (block->block_contents_size - *offset); i+=size)
6719                 {
6720                     if(tng_data->input_endianness_swap_func_32(tng_data,
6721                         (int32_t *)((char *)data->values + i))
6722                         != TNG_SUCCESS)
6723                     {
6724                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6725                                 __FILE__, __LINE__);
6726                     }
6727                 }
6728             }
6729             break;
6730         case TNG_INT_DATA:
6731         case TNG_DOUBLE_DATA:
6732             if(tng_data->input_endianness_swap_func_64)
6733             {
6734                 for(i = 0; i < (block->block_contents_size - *offset); i+=size)
6735                 {
6736                     if(tng_data->input_endianness_swap_func_64(tng_data,
6737                         (int64_t *)((char *)data->values + i))
6738                         != TNG_SUCCESS)
6739                     {
6740                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6741                                 __FILE__, __LINE__);
6742                     }
6743                 }
6744             }
6745             break;
6746         case TNG_CHAR_DATA:
6747             break;
6748         }
6749     }
6750     return(TNG_SUCCESS);
6751 }
6752
6753 /** Write a non-particle data block
6754  * @param tng_data is a trajectory data container.
6755  * @param block is the block to store the data (should already contain
6756  * the block headers and the block contents).
6757  * @param block_index is the index number of the data block in the frame set.
6758  * @param hash_mode is an option to decide whether to use the md5 hash or not.
6759  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
6760  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6761  * error has occured.
6762  */
6763 static tng_function_status tng_data_block_write(tng_trajectory_t tng_data,
6764                                                 tng_gen_block_t block,
6765                                                 const int64_t block_index,
6766                                                 const char hash_mode)
6767 {
6768     int64_t n_frames, stride_length, frame_step, data_start_pos;
6769     int64_t i, j;
6770     int offset = 0, size;
6771     unsigned int len;
6772 #ifdef USE_ZLIB
6773     tng_function_status stat;
6774 #endif
6775     char temp, dependency, *temp_name;
6776     double multiplier;
6777     tng_trajectory_frame_set_t frame_set =
6778     &tng_data->current_trajectory_frame_set;
6779
6780     tng_non_particle_data_t data;
6781     char block_type_flag;
6782
6783     /* If we have already started writing frame sets it is too late to write
6784      * non-trajectory data blocks */
6785     if(tng_data->current_trajectory_frame_set_output_file_pos > 0)
6786     {
6787         block_type_flag = TNG_TRAJECTORY_BLOCK;
6788     }
6789     else
6790     {
6791         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
6792     }
6793
6794     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
6795     {
6796         return(TNG_CRITICAL);
6797     }
6798
6799     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
6800     {
6801         data = &frame_set->tr_data[block_index];
6802
6803         /* If this data block has not had any data added in this frame set
6804          * do not write it. */
6805         if(data->first_frame_with_data < frame_set->first_frame)
6806         {
6807             return(TNG_SUCCESS);
6808         }
6809
6810         stride_length = tng_max_i64(1, data->stride_length);
6811     }
6812     else
6813     {
6814         data = &tng_data->non_tr_data[block_index];
6815         stride_length = 1;
6816     }
6817
6818     switch(data->datatype)
6819     {
6820     case TNG_CHAR_DATA:
6821         size = 1;
6822         break;
6823     case TNG_INT_DATA:
6824         size = sizeof(int64_t);
6825         break;
6826     case TNG_FLOAT_DATA:
6827         size = sizeof(float);
6828         break;
6829     case TNG_DOUBLE_DATA:
6830     default:
6831         size = sizeof(double);
6832     }
6833
6834     len = (unsigned int)strlen(data->block_name) + 1;
6835
6836     if(!block->name || strlen(block->name) < len)
6837     {
6838         temp_name = realloc(block->name, len);
6839         if(!temp_name)
6840         {
6841             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len+1,
6842                    __FILE__, __LINE__);
6843             free(block->name);
6844             block->name = 0;
6845             return(TNG_CRITICAL);
6846         }
6847         block->name = temp_name;
6848     }
6849     strncpy(block->name, data->block_name, len);
6850     block->id = data->block_id;
6851
6852     /* If writing frame independent data data->n_frames is 0, but n_frames
6853        is used for the loop writing the data (and reserving memory) and needs
6854        to be at least 1 */
6855     n_frames = tng_max_i64(1, data->n_frames);
6856
6857     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
6858     {
6859         /* If the frame set is finished before writing the full number of frames
6860            make sure the data block is not longer than the frame set. */
6861         n_frames = tng_min_i64(n_frames, frame_set->n_frames);
6862
6863         n_frames -= (data->first_frame_with_data - frame_set->first_frame);
6864     }
6865
6866     frame_step = (n_frames % stride_length) ? n_frames / stride_length + 1:
6867                  n_frames / stride_length;
6868
6869     /* TNG compression will use compression precision to get integers from
6870      * floating point data. The compression multiplier stores that information
6871      * to be able to return the precision of the compressed data. */
6872     if(data->codec_id == TNG_TNG_COMPRESSION)
6873     {
6874         data->compression_multiplier = tng_data->compression_precision;
6875     }
6876     /* Uncompressed data blocks do not use compression multipliers at all.
6877      * GZip compression does not need it either. */
6878     else if(data->codec_id == TNG_UNCOMPRESSED || data->codec_id == TNG_GZIP_COMPRESSION)
6879     {
6880         data->compression_multiplier = 1.0;
6881     }
6882
6883     if(block_type_flag == TNG_TRAJECTORY_BLOCK && data->n_frames > 0)
6884     {
6885         dependency = TNG_FRAME_DEPENDENT;
6886     }
6887     else
6888     {
6889         dependency = 0;
6890     }
6891
6892     if(tng_data_block_len_calculate(tng_data, (tng_particle_data_t)data, TNG_FALSE, n_frames,
6893                                     frame_step, stride_length, 0,
6894                                     1, dependency, &data_start_pos,
6895                                     &block->block_contents_size) != TNG_SUCCESS)
6896     {
6897         fprintf(stderr, "TNG library: Cannot calculate length of non-particle data block. %s: %d\n",
6898                 __FILE__, __LINE__);
6899         return(TNG_CRITICAL);
6900     }
6901
6902     if(block->block_contents)
6903     {
6904         free(block->block_contents);
6905     }
6906     block->block_contents = malloc(block->block_contents_size);
6907     if(!block->block_contents)
6908     {
6909         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
6910                block->block_contents_size, __FILE__, __LINE__);
6911         return(TNG_CRITICAL);
6912     }
6913
6914
6915     memcpy(block->block_contents, &data->datatype, sizeof(char));
6916     offset += sizeof(char);
6917
6918     memcpy(block->block_contents+offset, &dependency, sizeof(char));
6919     offset += sizeof(char);
6920
6921     if(dependency & TNG_FRAME_DEPENDENT)
6922     {
6923         if(stride_length > 1)
6924         {
6925             temp = 1;
6926         }
6927         else
6928         {
6929             temp = 0;
6930         }
6931         memcpy(block->block_contents+offset, &temp, sizeof(char));
6932         offset += sizeof(char);
6933     }
6934
6935     memcpy(block->block_contents+offset, &data->n_values_per_frame,
6936            sizeof(data->n_values_per_frame));
6937     if(tng_data->output_endianness_swap_func_64)
6938     {
6939         if(tng_data->output_endianness_swap_func_64(tng_data,
6940            (int64_t *)block->header_contents+offset)
6941             != TNG_SUCCESS)
6942         {
6943             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6944                     __FILE__, __LINE__);
6945         }
6946     }
6947     offset += sizeof(data->n_values_per_frame);
6948
6949     memcpy(block->block_contents+offset, &data->codec_id,
6950            sizeof(data->codec_id));
6951     if(tng_data->output_endianness_swap_func_64)
6952     {
6953         if(tng_data->output_endianness_swap_func_64(tng_data,
6954            (int64_t *)block->header_contents+offset)
6955             != TNG_SUCCESS)
6956         {
6957             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6958                     __FILE__, __LINE__);
6959         }
6960     }
6961     offset += sizeof(data->codec_id);
6962
6963     if(data->codec_id != TNG_UNCOMPRESSED)
6964     {
6965         memcpy(block->block_contents+offset, &data->compression_multiplier,
6966                sizeof(data->compression_multiplier));
6967         if(tng_data->output_endianness_swap_func_64)
6968         {
6969             if(tng_data->output_endianness_swap_func_64(tng_data,
6970             (int64_t *)block->header_contents+offset)
6971                 != TNG_SUCCESS)
6972             {
6973                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6974                         __FILE__, __LINE__);
6975             }
6976         }
6977         offset += sizeof(data->compression_multiplier);
6978     }
6979
6980     if(data->n_frames > 0 && stride_length > 1)
6981     {
6982         /* FIXME: first_frame_with_data is not reliably set */
6983         if(data->first_frame_with_data == 0)
6984         {
6985             data->first_frame_with_data = frame_set->first_frame;
6986         }
6987         memcpy(block->block_contents+offset, &data->first_frame_with_data,
6988                sizeof(data->first_frame_with_data));
6989         if(tng_data->output_endianness_swap_func_64)
6990         {
6991             if(tng_data->output_endianness_swap_func_64(tng_data,
6992             (int64_t *)block->header_contents+offset)
6993                 != TNG_SUCCESS)
6994             {
6995                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6996                         __FILE__, __LINE__);
6997             }
6998         }
6999         offset += sizeof(data->first_frame_with_data);
7000
7001         memcpy(block->block_contents+offset, &stride_length,
7002                sizeof(data->stride_length));
7003         if(tng_data->output_endianness_swap_func_64)
7004         {
7005             if(tng_data->output_endianness_swap_func_64(tng_data,
7006             (int64_t *)block->header_contents+offset)
7007                 != TNG_SUCCESS)
7008             {
7009                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7010                         __FILE__, __LINE__);
7011             }
7012         }
7013         offset += sizeof(data->stride_length);
7014     }
7015
7016     if(data->datatype == TNG_CHAR_DATA)
7017     {
7018         if(data->strings)
7019         {
7020             for(i = 0; i < frame_step; i++)
7021             {
7022                 for(j = 0; j < data->n_values_per_frame; j++)
7023                 {
7024                     len = (unsigned int)strlen(data->strings[i][j]) + 1;
7025                     strncpy(block->block_contents+offset, data->strings[i][j],
7026                             len);
7027                     offset += len;
7028                 }
7029             }
7030         }
7031     }
7032     else if(data->values)
7033     {
7034         memcpy(block->block_contents + offset, data->values,
7035                block->block_contents_size - offset);
7036         switch(data->datatype)
7037         {
7038         case TNG_FLOAT_DATA:
7039             if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
7040                data->codec_id == TNG_TNG_COMPRESSION)
7041             {
7042                 if(tng_data->input_endianness_swap_func_32)
7043                 {
7044                     for(i = offset; i < block->block_contents_size; i+=size)
7045                     {
7046                         if(tng_data->input_endianness_swap_func_32(tng_data,
7047                            (int32_t *)(block->block_contents + i))
7048                            != TNG_SUCCESS)
7049                         {
7050                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7051                                     __FILE__, __LINE__);
7052                         }
7053                     }
7054                 }
7055             }
7056             else
7057             {
7058                 multiplier = data->compression_multiplier;
7059                 if(fabs(multiplier - 1.0) > 0.00001 ||
7060                    tng_data->input_endianness_swap_func_32)
7061                 {
7062                     for(i = offset; block->block_contents_size; i+=size)
7063                     {
7064                         *(float *)(block->block_contents + i) *= (float)multiplier;
7065                         if(tng_data->input_endianness_swap_func_32 &&
7066                         tng_data->input_endianness_swap_func_32(tng_data,
7067                         (int32_t *)(block->block_contents + i))
7068                         != TNG_SUCCESS)
7069                         {
7070                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7071                                     __FILE__, __LINE__);
7072                         }
7073                     }
7074                 }
7075             }
7076             break;
7077         case TNG_INT_DATA:
7078             if(tng_data->input_endianness_swap_func_64)
7079             {
7080                 for(i = offset; i < block->block_contents_size; i+=size)
7081                 {
7082                     if(tng_data->input_endianness_swap_func_64(tng_data,
7083                        (int64_t *)(block->block_contents + i))
7084                        != TNG_SUCCESS)
7085                     {
7086                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7087                                 __FILE__, __LINE__);
7088                     }
7089                 }
7090             }
7091             break;
7092         case TNG_DOUBLE_DATA:
7093             if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
7094                data->codec_id == TNG_TNG_COMPRESSION)
7095             {
7096                 if(tng_data->input_endianness_swap_func_64)
7097                 {
7098                     for(i = offset; i < block->block_contents_size; i+=size)
7099                     {
7100                         if(tng_data->input_endianness_swap_func_64(tng_data,
7101                            (int64_t *)(block->block_contents + i))
7102                            != TNG_SUCCESS)
7103                         {
7104                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7105                                     __FILE__, __LINE__);
7106                         }
7107                     }
7108                 }
7109             }
7110             else
7111             {
7112                 multiplier = data->compression_multiplier;
7113                 if(fabs(multiplier - 1.0) > 0.00001 ||
7114                    tng_data->input_endianness_swap_func_64)
7115                 {
7116                     for(i = offset; i < block->block_contents_size; i+=size)
7117                     {
7118                         *(double *)(block->block_contents + i) *= multiplier;
7119                         if(tng_data->input_endianness_swap_func_64 &&
7120                         tng_data->input_endianness_swap_func_64(tng_data,
7121                         (int64_t *)(block->block_contents + i))
7122                         != TNG_SUCCESS)
7123                         {
7124                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7125                                     __FILE__, __LINE__);
7126                         }
7127                     }
7128                 }
7129             }
7130             break;
7131         case TNG_CHAR_DATA:
7132             break;
7133         }
7134     }
7135     else
7136     {
7137         memset(block->block_contents+offset, 0, block->block_contents_size - offset);
7138     }
7139
7140     frame_set->n_written_frames += frame_set->n_unwritten_frames;
7141     frame_set->n_unwritten_frames = 0;
7142
7143     if(block_type_flag == TNG_NON_TRAJECTORY_BLOCK || frame_set->n_written_frames > 0)
7144     {
7145         switch(data->codec_id)
7146         {
7147 #ifdef USE_ZLIB
7148         case TNG_GZIP_COMPRESSION:
7149     /*         fprintf(stderr, "TNG library: Before compression: %"PRId64"\n", block->block_contents_size); */
7150             stat = tng_gzip_compress(tng_data, block,
7151                                      block->block_contents + data_start_pos,
7152                                      block->block_contents_size - data_start_pos);
7153             if(stat != TNG_SUCCESS)
7154             {
7155                 fprintf(stderr, "TNG library: Could not write gzipped block data. %s: %d\n", __FILE__,
7156                     __LINE__);
7157                 if(stat == TNG_CRITICAL)
7158                 {
7159                     return(TNG_CRITICAL);
7160                 }
7161                 data->codec_id = TNG_UNCOMPRESSED;
7162             }
7163     /*         fprintf(stderr, "TNG library: After compression: %"PRId64"\n", block->block_contents_size); */
7164             break;
7165 #endif
7166         }
7167     }
7168
7169     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
7170     {
7171         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
7172                tng_data->output_file_path, __FILE__, __LINE__);
7173         return(TNG_CRITICAL);
7174     }
7175
7176     if(fwrite(block->block_contents, block->block_contents_size, 1,
7177               tng_data->output_file) != 1)
7178     {
7179         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n",
7180                __FILE__, __LINE__);
7181         return(TNG_CRITICAL);
7182     }
7183
7184     return(TNG_SUCCESS);
7185 }
7186
7187 /** Read the meta information of a data block (particle or non-particle data).
7188  * @param tng_data is a trajectory data container.
7189  * @param block is the block to store the data (should already contain
7190  * the block headers).
7191  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
7192  * error has occured.
7193  */
7194 static tng_function_status tng_data_block_meta_information_read
7195                 (tng_trajectory_t tng_data,
7196                  tng_gen_block_t block,
7197                  int *offset,
7198                  char *datatype,
7199                  char *dependency,
7200                  char *sparse_data,
7201                  int64_t *n_values,
7202                  int64_t *codec_id,
7203                  int64_t *first_frame_with_data,
7204                  int64_t *stride_length,
7205                  int64_t *n_frames,
7206                  int64_t *num_first_particle,
7207                  int64_t *block_n_particles,
7208                  double *multiplier)
7209 {
7210     int meta_size;
7211     char *contents;
7212
7213     if(block->block_contents)
7214     {
7215         contents = block->block_contents;
7216     }
7217     else
7218     {
7219         meta_size = 3 * sizeof(char) + sizeof(double) + 6 * sizeof(int64_t);
7220         contents = malloc(meta_size);
7221         if(!contents)
7222         {
7223             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
7224                meta_size, __FILE__, __LINE__);
7225         }
7226
7227         if(fread(contents, meta_size, 1, tng_data->input_file) == 0)
7228         {
7229             fprintf(stderr, "TNG library: Cannot read data block meta information. %s: %d\n", __FILE__, __LINE__);
7230             free(contents);
7231             return(TNG_CRITICAL);
7232         }
7233     }
7234
7235     memcpy(datatype, contents+*offset,
7236            sizeof(*datatype));
7237     *offset += sizeof(*datatype);
7238
7239     memcpy(dependency, contents+*offset,
7240            sizeof(*dependency));
7241     *offset += sizeof(*dependency);
7242
7243     if(*dependency & TNG_FRAME_DEPENDENT)
7244     {
7245         memcpy(sparse_data, contents+*offset,
7246                sizeof(*sparse_data));
7247         *offset += sizeof(*sparse_data);
7248     }
7249
7250     memcpy(n_values, contents+*offset,
7251         sizeof(*n_values));
7252     if(tng_data->input_endianness_swap_func_64)
7253     {
7254         if(tng_data->input_endianness_swap_func_64(tng_data,
7255                                                    n_values)
7256             != TNG_SUCCESS)
7257         {
7258             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7259                     __FILE__, __LINE__);
7260         }
7261     }
7262     *offset += sizeof(*n_values);
7263
7264     memcpy(codec_id, contents+*offset,
7265         sizeof(*codec_id));
7266     if(tng_data->input_endianness_swap_func_64)
7267     {
7268         if(tng_data->input_endianness_swap_func_64(tng_data,
7269                                                    codec_id)
7270             != TNG_SUCCESS)
7271         {
7272             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7273                     __FILE__, __LINE__);
7274         }
7275     }
7276     *offset += sizeof(*codec_id);
7277
7278     if(*codec_id != TNG_UNCOMPRESSED)
7279     {
7280         memcpy(multiplier, contents+*offset,
7281             sizeof(*multiplier));
7282         if(tng_data->input_endianness_swap_func_64)
7283         {
7284             if(tng_data->input_endianness_swap_func_64(tng_data,
7285                                                        (int64_t *) multiplier)
7286                 != TNG_SUCCESS)
7287             {
7288                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7289                         __FILE__, __LINE__);
7290             }
7291         }
7292         *offset += sizeof(*multiplier);
7293     }
7294     else
7295     {
7296         *multiplier = 1;
7297     }
7298
7299     if(*dependency & TNG_FRAME_DEPENDENT)
7300     {
7301         if(*sparse_data)
7302         {
7303             memcpy(first_frame_with_data, contents+*offset,
7304                 sizeof(*first_frame_with_data));
7305             if(tng_data->input_endianness_swap_func_64)
7306             {
7307                 if(tng_data->input_endianness_swap_func_64(tng_data,
7308                                                            first_frame_with_data)
7309                     != TNG_SUCCESS)
7310                 {
7311                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7312                             __FILE__, __LINE__);
7313                 }
7314             }
7315             *offset += sizeof(*first_frame_with_data);
7316
7317             memcpy(stride_length, contents+*offset,
7318                 sizeof(*stride_length));
7319             if(tng_data->input_endianness_swap_func_64)
7320             {
7321                 if(tng_data->input_endianness_swap_func_64(tng_data,
7322                                                            stride_length)
7323                     != TNG_SUCCESS)
7324                 {
7325                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7326                             __FILE__, __LINE__);
7327                 }
7328             }
7329             *offset += sizeof(*stride_length);
7330             *n_frames = tng_data->current_trajectory_frame_set.n_frames -
7331                         (*first_frame_with_data -
7332                         tng_data->current_trajectory_frame_set.first_frame);
7333         }
7334         else
7335         {
7336             *first_frame_with_data = 0;
7337             *stride_length = 1;
7338             *n_frames = tng_data->current_trajectory_frame_set.n_frames;
7339         }
7340     }
7341     else
7342     {
7343         *first_frame_with_data = 0;
7344         *stride_length = 1;
7345         *n_frames = 1;
7346     }
7347
7348     if (*dependency & TNG_PARTICLE_DEPENDENT)
7349     {
7350         memcpy(num_first_particle, contents+*offset,
7351                sizeof(*num_first_particle));
7352         if(tng_data->input_endianness_swap_func_64)
7353         {
7354             if(tng_data->input_endianness_swap_func_64(tng_data,
7355                                                        num_first_particle)
7356                 != TNG_SUCCESS)
7357             {
7358                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7359                         __FILE__, __LINE__);
7360             }
7361         }
7362         *offset += sizeof(*num_first_particle);
7363
7364         memcpy(block_n_particles, contents+*offset,
7365             sizeof(*block_n_particles));
7366         if(tng_data->input_endianness_swap_func_64)
7367         {
7368             if(tng_data->input_endianness_swap_func_64(tng_data,
7369                                                        block_n_particles)
7370                 != TNG_SUCCESS)
7371             {
7372                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7373                         __FILE__, __LINE__);
7374             }
7375         }
7376         *offset += sizeof(*block_n_particles);
7377     }
7378
7379     if(!block->block_contents)
7380     {
7381         free(contents);
7382     }
7383     return(TNG_SUCCESS);
7384 }
7385
7386 /** Read the contents of a data block (particle or non-particle data).
7387  * @param tng_data is a trajectory data container.
7388  * @param block is the block to store the data (should already contain
7389  * the block headers).
7390  * @param hash_mode is an option to decide whether to use the md5 hash or not.
7391  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
7392  * compared to the md5 hash of the read contents to ensure valid data.
7393  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
7394  * error has occured.
7395  */
7396 static tng_function_status tng_data_block_contents_read
7397                 (tng_trajectory_t tng_data,
7398                  tng_gen_block_t block,
7399                  const char hash_mode)
7400 {
7401     int64_t n_values, codec_id, n_frames, first_frame_with_data;
7402     int64_t stride_length, block_n_particles, num_first_particle;
7403     double multiplier;
7404     char datatype, dependency, sparse_data;
7405     int offset = 0;
7406     tng_bool same_hash;
7407
7408     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
7409     {
7410         return(TNG_CRITICAL);
7411     }
7412
7413     if(block->block_contents)
7414     {
7415         free(block->block_contents);
7416     }
7417
7418     block->block_contents = malloc(block->block_contents_size);
7419     if(!block->block_contents)
7420     {
7421         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7422                block->block_contents_size, __FILE__, __LINE__);
7423         return(TNG_CRITICAL);
7424     }
7425
7426     /* Read the whole block into block_contents to be able to write it to
7427      * disk even if it cannot be interpreted. */
7428     if(fread(block->block_contents, block->block_contents_size, 1,
7429              tng_data->input_file) == 0)
7430     {
7431         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
7432         return(TNG_CRITICAL);
7433     }
7434
7435     /* FIXME: Does not check if the size of the contents matches the expected
7436      * size or if the contents can be read. */
7437
7438     if(hash_mode == TNG_USE_HASH)
7439     {
7440         tng_md5_hash_match_verify(block, &same_hash);
7441         if(same_hash != TNG_TRUE)
7442         {
7443             fprintf(stderr, "TNG library: '%s' data block contents corrupt. Hashes do not match. %s: %d\n",
7444                 block->name, __FILE__, __LINE__);
7445     /*         return(TNG_FAILURE); */
7446         }
7447     }
7448
7449     if(tng_data_block_meta_information_read(tng_data, block,
7450                                             &offset, &datatype,
7451                                             &dependency, &sparse_data,
7452                                             &n_values, &codec_id,
7453                                             &first_frame_with_data,
7454                                             &stride_length, &n_frames,
7455                                             &num_first_particle,
7456                                             &block_n_particles,
7457                                             &multiplier) == TNG_CRITICAL)
7458     {
7459         fprintf(stderr, "TNG library: Cannot read data block (%s) meta information. %s: %d\n",
7460             block->name, __FILE__, __LINE__);
7461         return(TNG_CRITICAL);
7462     }
7463
7464     if (dependency & TNG_PARTICLE_DEPENDENT)
7465     {
7466         return(tng_particle_data_read(tng_data, block,
7467                                       &offset, datatype,
7468                                       num_first_particle,
7469                                       block_n_particles,
7470                                       first_frame_with_data,
7471                                       stride_length,
7472                                       n_frames, n_values,
7473                                       codec_id, multiplier));
7474     }
7475     else
7476     {
7477         return(tng_data_read(tng_data, block,
7478                              &offset, datatype,
7479                              first_frame_with_data,
7480                              stride_length,
7481                              n_frames, n_values,
7482                              codec_id, multiplier));
7483     }
7484 }
7485
7486 /*
7487 // ** Move the blocks in a frame set so that there is no unused space between
7488 //  * them. This can only be done on the last frame set in the file and should
7489 //  * be done e.g. if the last frame set in the file has fewer frames than
7490 //  * default or after compressing data blocks in a frame set.
7491 //  * @param tng_data is a trajectory data container.
7492 //  * @details the current_trajectory_frame_set is the one that will be modified.
7493 //  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the frame set
7494 //  * cannot be aligned or TNG_CRITICAL (2) if a major error has occured.
7495 //  * FIXME: This function is not finished!!!
7496 //  *
7497 // static tng_function_status tng_frame_set_align(tng_trajectory_t tng_data)
7498 // {
7499 //     tng_gen_block_t block;
7500 //     tng_trajectory_frame_set_t frame_set;
7501 //     FILE *temp = tng_data->input_file;
7502 //     int64_t pos, contents_start_pos, output_file_len;
7503 //
7504 //     frame_set = &tng_data->current_trajectory_frame_set;
7505 //
7506 //     if(frame_set->n_written_frames == frame_set->n_frames)
7507 //     {
7508 //         return(TNG_SUCCESS);
7509 //     }
7510 //
7511 //     if(tng_data->current_trajectory_frame_set_output_file_pos !=
7512 //        tng_data->last_trajectory_frame_set_output_file_pos)
7513 //     {
7514 //     }
7515 //
7516 //     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
7517 //     {
7518 //         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
7519 //                __FILE__, __LINE__);
7520 //         return(TNG_CRITICAL);
7521 //     }
7522 //
7523 //     tng_block_init(&block);
7524 // //     output_file_pos = ftell(tng_data->output_file);
7525 //
7526 //     tng_data->input_file = tng_data->output_file;
7527 //
7528 //     pos = tng_data->current_trajectory_frame_set_output_file_pos;
7529 //
7530 //     fseek(tng_data->output_file, pos, SEEK_SET);
7531 //     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
7532 //     {
7533 //         fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
7534 //             __FILE__, __LINE__);
7535 //         tng_data->input_file = temp;
7536 //         tng_block_destroy(&block);
7537 //         return(TNG_CRITICAL);
7538 //     }
7539 //
7540 //     contents_start_pos = ftell(tng_data->output_file);
7541 //
7542 //     fseek(tng_data->output_file, 0, SEEK_END);
7543 //     output_file_len = ftell(tng_data->output_file);
7544 //     pos = contents_start_pos + block->block_contents_size;
7545 //     fseek(tng_data->output_file, pos,
7546 //           SEEK_SET);
7547 //
7548 //     while(pos < output_file_len)
7549 //     {
7550 //         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
7551 //         {
7552 //             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", pos,
7553 //                    __FILE__, __LINE__);
7554 //             tng_data->input_file = temp;
7555 //             tng_block_destroy(&block);
7556 //             return(TNG_CRITICAL);
7557 //         }
7558 //         pos += block->header_contents_size + block->block_contents_size;
7559 //         fseek(tng_data->output_file, pos, SEEK_SET);
7560 //     }
7561 //
7562 //     return(TNG_SUCCESS);
7563 // }
7564 */
7565 /** Finish writing the current frame set. Update the number of frames
7566  * and the hashes of the frame set and all its data blocks (if hash_mode
7567  * == TNG_USE_HASH).
7568  * @param tng_data is a trajectory data container.
7569  * @param hash_mode specifies whether to update the block md5 hash when
7570  * updating the pointers.
7571  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
7572  * error has occured.
7573  */
7574 static tng_function_status tng_frame_set_finalize
7575                 (tng_trajectory_t tng_data, const char hash_mode)
7576 {
7577     tng_gen_block_t block;
7578     tng_trajectory_frame_set_t frame_set;
7579     FILE *temp = tng_data->input_file;
7580     int64_t pos, contents_start_pos, output_file_len;
7581
7582     frame_set = &tng_data->current_trajectory_frame_set;
7583
7584     if(frame_set->n_written_frames == frame_set->n_frames)
7585     {
7586         return(TNG_SUCCESS);
7587     }
7588
7589     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
7590     {
7591         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
7592                __FILE__, __LINE__);
7593         return(TNG_CRITICAL);
7594     }
7595
7596     tng_block_init(&block);
7597 /*     output_file_pos = ftell(tng_data->output_file); */
7598
7599     tng_data->input_file = tng_data->output_file;
7600
7601     pos = tng_data->current_trajectory_frame_set_output_file_pos;
7602
7603     fseek(tng_data->output_file, (long)pos, SEEK_SET);
7604
7605     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
7606     {
7607         fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
7608             __FILE__, __LINE__);
7609         tng_data->input_file = temp;
7610         tng_block_destroy(&block);
7611         return(TNG_CRITICAL);
7612     }
7613
7614     contents_start_pos = ftell(tng_data->output_file);
7615
7616     fseek(tng_data->output_file, sizeof(frame_set->first_frame), SEEK_CUR);
7617     if(fwrite(&frame_set->n_written_frames, sizeof(frame_set->n_frames),
7618               1, tng_data->output_file) != 1)
7619     {
7620         tng_data->input_file = temp;
7621         tng_block_destroy(&block);
7622         return(TNG_CRITICAL);
7623     }
7624
7625
7626     if(hash_mode == TNG_USE_HASH)
7627     {
7628         tng_md5_hash_update(tng_data, block, pos,
7629                             pos + block->header_contents_size);
7630     }
7631
7632     fseek(tng_data->output_file, 0, SEEK_END);
7633     output_file_len = ftell(tng_data->output_file);
7634     pos = contents_start_pos + block->block_contents_size;
7635     fseek(tng_data->output_file, (long)pos, SEEK_SET);
7636
7637     while(pos < output_file_len)
7638     {
7639         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
7640         {
7641             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", pos,
7642                    __FILE__, __LINE__);
7643             tng_data->input_file = temp;
7644             tng_block_destroy(&block);
7645             return(TNG_CRITICAL);
7646         }
7647
7648         if(hash_mode == TNG_USE_HASH)
7649         {
7650             tng_md5_hash_update(tng_data, block, pos,
7651                                 pos + block->header_contents_size);
7652         }
7653         pos += block->header_contents_size + block->block_contents_size;
7654         fseek(tng_data->output_file, (long)pos, SEEK_SET);
7655     }
7656
7657     tng_data->input_file = temp;
7658     tng_block_destroy(&block);
7659     return(TNG_SUCCESS);
7660 }
7661
7662 /*
7663 // ** Sets the name of a file contents block
7664 //  * @param tng_data is a trajectory data container.
7665 //  * @param block is the block, of which to change names.
7666 //  * @param new_name is the new name of the block.
7667 //  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
7668 //  * error has occured.
7669 //
7670 // static tng_function_status tng_block_name_set(tng_trajectory_t tng_data,
7671 //                                               tng_gen_block_t block,
7672 //                                               const char *new_name)
7673 // {
7674 //     int len;
7675 //
7676 //     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
7677 //
7678 //      * If the currently stored string length is not enough to store the new
7679 //      * string it is freed and reallocated. *
7680 //     if(block->name && strlen(block->name) < len)
7681 //     {
7682 //         free(block->name);
7683 //         block->name = 0;
7684 //     }
7685 //     if(!block->name)
7686 //     {
7687 //         block->name = malloc(len);
7688 //         if(!block->name)
7689 //         {
7690 //             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
7691 //                    __FILE__, __LINE__);
7692 //             return(TNG_CRITICAL);
7693 //         }
7694 //     }
7695 //
7696 //     strncpy(block->name, new_name, len);
7697 //
7698 //     return(TNG_SUCCESS);
7699 // }
7700 */
7701
7702 tng_function_status tng_atom_residue_get(const tng_trajectory_t tng_data,
7703                                          const tng_atom_t atom,
7704                                          tng_residue_t *residue)
7705 {
7706     (void) tng_data;
7707
7708     TNG_ASSERT(atom, "TNG library: atom must not be NULL");
7709
7710     *residue = atom->residue;
7711
7712     return(TNG_SUCCESS);
7713 }
7714
7715 tng_function_status tng_atom_name_get(const tng_trajectory_t tng_data,
7716                                       const tng_atom_t atom,
7717                                       char *name,
7718                                       const int max_len)
7719 {
7720     (void) tng_data;
7721     TNG_ASSERT(atom, "TNG library: atom must not be NULL");
7722     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
7723
7724     strncpy(name, atom->name, max_len - 1);
7725     name[max_len - 1] = 0;
7726
7727     if(strlen(atom->name) > (unsigned int)max_len - 1)
7728     {
7729         return(TNG_FAILURE);
7730     }
7731     return(TNG_SUCCESS);
7732 }
7733
7734 tng_function_status tng_atom_name_set(tng_trajectory_t tng_data,
7735                                       tng_atom_t atom,
7736                                       const char *new_name)
7737 {
7738     unsigned int len;
7739     (void)tng_data;
7740
7741     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7742     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
7743
7744     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
7745
7746     /* If the currently stored string length is not enough to store the new
7747      * string it is freed and reallocated. */
7748     if(atom->name && strlen(atom->name) < len)
7749     {
7750         free(atom->name);
7751         atom->name = 0;
7752     }
7753     if(!atom->name)
7754     {
7755         atom->name = malloc(len);
7756         if(!atom->name)
7757         {
7758             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
7759                    __FILE__, __LINE__);
7760             return(TNG_CRITICAL);
7761         }
7762     }
7763
7764     strncpy(atom->name, new_name, len);
7765
7766     return(TNG_SUCCESS);
7767 }
7768
7769 tng_function_status tng_atom_type_get(const tng_trajectory_t tng_data,
7770                                       const tng_atom_t atom,
7771                                       char *type,
7772                                       const int max_len)
7773 {
7774     (void) tng_data;
7775     TNG_ASSERT(atom, "TNG library: atom must not be NULL");
7776     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer");
7777
7778     strncpy(type, atom->atom_type, max_len - 1);
7779     type[max_len - 1] = 0;
7780
7781     if(strlen(atom->atom_type) > (unsigned int)max_len - 1)
7782     {
7783         return(TNG_FAILURE);
7784     }
7785     return(TNG_SUCCESS);
7786 }
7787
7788 tng_function_status tng_atom_type_set(tng_trajectory_t tng_data,
7789                                       tng_atom_t atom,
7790                                       const char *new_type)
7791 {
7792     unsigned int len;
7793     (void)tng_data;
7794
7795     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7796     TNG_ASSERT(new_type, "TNG library: new_type must not be a NULL pointer.");
7797
7798     len = tng_min_i((int)strlen(new_type) + 1, TNG_MAX_STR_LEN);
7799
7800     /* If the currently stored string length is not enough to store the new
7801      * string it is freed and reallocated. */
7802     if(atom->atom_type && strlen(atom->atom_type) < len)
7803     {
7804         free(atom->atom_type);
7805         atom->atom_type = 0;
7806     }
7807     if(!atom->atom_type)
7808     {
7809         atom->atom_type = malloc(len);
7810         if(!atom->atom_type)
7811         {
7812             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
7813                    __FILE__, __LINE__);
7814             return(TNG_CRITICAL);
7815         }
7816     }
7817
7818     strncpy(atom->atom_type, new_type, len);
7819
7820     return(TNG_SUCCESS);
7821 }
7822
7823 /** Initialise an atom struct
7824  * @param atom is the atom to initialise.
7825  * @return TNG_SUCCESS (0) if successful.
7826  */
7827 static tng_function_status tng_atom_init(tng_atom_t atom)
7828 {
7829     atom->name = 0;
7830     atom->atom_type = 0;
7831
7832     return(TNG_SUCCESS);
7833 }
7834
7835 /** Free the memory in an atom struct
7836  * @param atom is the atom to destroy.
7837  * @return TNG_SUCCESS (0) if successful.
7838  */
7839 static tng_function_status tng_atom_destroy(tng_atom_t atom)
7840 {
7841     if(atom->name)
7842     {
7843         free(atom->name);
7844         atom->name = 0;
7845     }
7846     if(atom->atom_type)
7847     {
7848         free(atom->atom_type);
7849         atom->atom_type = 0;
7850     }
7851
7852     return(TNG_SUCCESS);
7853 }
7854
7855 tng_function_status DECLSPECDLLEXPORT tng_version_major
7856                 (const tng_trajectory_t tng_data,
7857                  int *version)
7858 {
7859     (void)tng_data;
7860
7861     *version = TNG_VERSION_MAJOR;
7862
7863     return(TNG_SUCCESS);
7864 }
7865
7866 tng_function_status DECLSPECDLLEXPORT tng_version_minor
7867                 (const tng_trajectory_t tng_data,
7868                  int *version)
7869 {
7870     (void)tng_data;
7871
7872     *version = TNG_VERSION_MINOR;
7873
7874     return(TNG_SUCCESS);
7875 }
7876
7877 tng_function_status DECLSPECDLLEXPORT tng_version_patchlevel
7878                 (const tng_trajectory_t tng_data,
7879                  int *patch_level)
7880 {
7881     (void)tng_data;
7882
7883     *patch_level = TNG_VERSION_PATCHLEVEL;
7884
7885     return(TNG_SUCCESS);
7886 }
7887
7888 tng_function_status DECLSPECDLLEXPORT tng_version
7889                 (const tng_trajectory_t tng_data,
7890                  char *version,
7891                  const int max_len)
7892 {
7893     (void)tng_data;
7894     TNG_ASSERT(version, "TNG library: version must not be a NULL pointer");
7895
7896     TNG_SNPRINTF(version, max_len, "%s", TNG_VERSION);
7897
7898     return(TNG_SUCCESS);
7899 }
7900
7901 tng_function_status DECLSPECDLLEXPORT tng_molecule_add
7902                 (tng_trajectory_t tng_data,
7903                  const char *name,
7904                  tng_molecule_t *molecule)
7905 {
7906     int64_t id;
7907
7908     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7909     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7910
7911     /* Set ID to the ID of the last molecule + 1 */
7912     if(tng_data->n_molecules)
7913     {
7914         id = tng_data->molecules[tng_data->n_molecules-1].id + 1;
7915     }
7916     else
7917     {
7918         id = 1;
7919     }
7920
7921     return(tng_molecule_w_id_add(tng_data, name, id, molecule));
7922 }
7923
7924 tng_function_status DECLSPECDLLEXPORT tng_molecule_w_id_add
7925                 (tng_trajectory_t tng_data,
7926                  const char *name,
7927                  const int64_t id,
7928                  tng_molecule_t *molecule)
7929 {
7930     tng_molecule_t new_molecules;
7931     int64_t *new_molecule_cnt_list;
7932     tng_function_status stat = TNG_SUCCESS;
7933
7934     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7935     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7936
7937     new_molecules = realloc(tng_data->molecules,
7938                             sizeof(struct tng_molecule) *
7939                             (tng_data->n_molecules + 1));
7940
7941     if(!new_molecules)
7942     {
7943         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7944                sizeof(struct tng_molecule) * (tng_data->n_molecules + 1),
7945                __FILE__, __LINE__);
7946         free(tng_data->molecules);
7947         tng_data->molecules = 0;
7948         return(TNG_CRITICAL);
7949     }
7950
7951     new_molecule_cnt_list = realloc(tng_data->molecule_cnt_list,
7952                                     sizeof(int64_t) *
7953                                     (tng_data->n_molecules + 1));
7954
7955     if(!new_molecule_cnt_list)
7956     {
7957         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7958                sizeof(int64_t) * (tng_data->n_molecules + 1),
7959                __FILE__, __LINE__);
7960         free(tng_data->molecule_cnt_list);
7961         tng_data->molecule_cnt_list = 0;
7962         free(new_molecules);
7963         return(TNG_CRITICAL);
7964     }
7965
7966     tng_data->molecules = new_molecules;
7967     tng_data->molecule_cnt_list = new_molecule_cnt_list;
7968
7969     *molecule = &new_molecules[tng_data->n_molecules];
7970
7971     tng_molecule_init(tng_data, *molecule);
7972     tng_molecule_name_set(tng_data, *molecule, name);
7973
7974     /* FIXME: Should this be a function argument instead? */
7975     tng_data->molecule_cnt_list[tng_data->n_molecules] = 0;
7976
7977     (*molecule)->id = id;
7978
7979     tng_data->n_molecules++;
7980
7981     return(stat);
7982 }
7983
7984 tng_function_status DECLSPECDLLEXPORT tng_molecule_existing_add
7985                 (tng_trajectory_t tng_data,
7986                  tng_molecule_t *molecule_p)
7987 {
7988     int64_t *new_molecule_cnt_list, id;
7989     tng_molecule_t new_molecules, molecule;
7990
7991     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7992
7993     /* Set ID to the ID of the last molecule + 1 */
7994     if(tng_data->n_molecules)
7995     {
7996         id = tng_data->molecules[tng_data->n_molecules-1].id + 1;
7997     }
7998     else
7999     {
8000         id = 1;
8001     }
8002
8003     new_molecules = realloc(tng_data->molecules,
8004                             sizeof(struct tng_molecule) *
8005                             (tng_data->n_molecules + 1));
8006
8007     if(!new_molecules)
8008     {
8009         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8010                sizeof(struct tng_molecule) * (tng_data->n_molecules + 1),
8011                __FILE__, __LINE__);
8012         free(tng_data->molecules);
8013         tng_data->molecules = 0;
8014         return(TNG_CRITICAL);
8015     }
8016
8017     new_molecule_cnt_list = realloc(tng_data->molecule_cnt_list,
8018                                     sizeof(int64_t) *
8019                                     (tng_data->n_molecules + 1));
8020
8021     if(!new_molecule_cnt_list)
8022     {
8023         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8024                sizeof(int64_t) * (tng_data->n_molecules + 1),
8025                __FILE__, __LINE__);
8026         free(tng_data->molecule_cnt_list);
8027         tng_data->molecule_cnt_list = 0;
8028         free(new_molecules);
8029         return(TNG_CRITICAL);
8030     }
8031
8032     molecule = *molecule_p;
8033
8034     tng_data->molecules = new_molecules;
8035     tng_data->molecule_cnt_list = new_molecule_cnt_list;
8036
8037     new_molecules[tng_data->n_molecules] = *molecule;
8038
8039     tng_data->molecule_cnt_list[tng_data->n_molecules] = 0;
8040
8041     free(*molecule_p);
8042
8043     molecule = &new_molecules[tng_data->n_molecules];
8044
8045     *molecule_p = molecule;
8046
8047     molecule->id = id;
8048
8049     tng_data->n_molecules++;
8050
8051     return(TNG_SUCCESS);
8052 }
8053
8054 tng_function_status tng_molecule_name_get(const tng_trajectory_t tng_data,
8055                                           const tng_molecule_t molecule,
8056                                           char *name,
8057                                           const int max_len)
8058 {
8059     (void) tng_data;
8060     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
8061     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
8062
8063     strncpy(name, molecule->name, max_len - 1);
8064     name[max_len - 1] = 0;
8065
8066     if(strlen(molecule->name) > (unsigned int)max_len - 1)
8067     {
8068         return(TNG_FAILURE);
8069     }
8070     return(TNG_SUCCESS);
8071 }
8072
8073 tng_function_status DECLSPECDLLEXPORT tng_molecule_name_set
8074                 (tng_trajectory_t tng_data,
8075                  tng_molecule_t molecule,
8076                  const char *new_name)
8077 {
8078     unsigned int len;
8079     (void)tng_data;
8080
8081     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8082     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
8083
8084     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
8085
8086     /* If the currently stored string length is not enough to store the new
8087      * string it is freed and reallocated. */
8088     if(molecule->name && strlen(molecule->name) < len)
8089     {
8090         free(molecule->name);
8091         molecule->name = 0;
8092     }
8093     if(!molecule->name)
8094     {
8095         molecule->name = malloc(len);
8096         if(!molecule->name)
8097         {
8098             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
8099                    __FILE__, __LINE__);
8100             return(TNG_CRITICAL);
8101         }
8102     }
8103
8104     strncpy(molecule->name, new_name, len);
8105
8106     return(TNG_SUCCESS);
8107 }
8108
8109 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_get
8110                 (const tng_trajectory_t tng_data,
8111                  const tng_molecule_t molecule,
8112                  int64_t *cnt)
8113 {
8114     int64_t i, index = -1;
8115
8116     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8117     TNG_ASSERT(cnt, "TNG library: cnt must not be a NULL pointer.");
8118
8119     for(i = 0; i < tng_data->n_molecules; i++)
8120     {
8121         if(&tng_data->molecules[i] == molecule)
8122         {
8123             index = i;
8124             break;
8125         }
8126     }
8127     if(index == -1)
8128     {
8129         return(TNG_FAILURE);
8130     }
8131     *cnt = tng_data->molecule_cnt_list[index];
8132
8133     return(TNG_SUCCESS);
8134 }
8135
8136 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_set
8137                 (tng_trajectory_t tng_data,
8138                  tng_molecule_t molecule,
8139                  const int64_t cnt)
8140 {
8141     int64_t i, old_cnt, index = -1;
8142
8143     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8144
8145     for(i = 0; i < tng_data->n_molecules; i++)
8146     {
8147         if(&tng_data->molecules[i] == molecule)
8148         {
8149             index = i;
8150             break;
8151         }
8152     }
8153     if(index == -1)
8154     {
8155         fprintf(stderr, "TNG library: Could not find molecule in TNG trajectory. %s: %d\n",
8156                __FILE__, __LINE__);
8157         return(TNG_FAILURE);
8158     }
8159     if(tng_data->var_num_atoms_flag == TNG_CONSTANT_N_ATOMS)
8160     {
8161         old_cnt = tng_data->molecule_cnt_list[index];
8162         tng_data->molecule_cnt_list[index] = cnt;
8163
8164         tng_data->n_particles += (cnt-old_cnt) *
8165                                  tng_data->molecules[index].n_atoms;
8166     }
8167     else
8168     {
8169         old_cnt = tng_data->current_trajectory_frame_set.molecule_cnt_list[index];
8170         tng_data->current_trajectory_frame_set.molecule_cnt_list[index] = cnt;
8171
8172         tng_data->current_trajectory_frame_set.n_particles += (cnt-old_cnt) *
8173                 tng_data->molecules[index].n_atoms;
8174     }
8175
8176     return(TNG_SUCCESS);
8177 }
8178
8179 tng_function_status DECLSPECDLLEXPORT tng_molecule_find
8180                 (tng_trajectory_t tng_data,
8181                  const char *name,
8182                  int64_t nr,
8183                  tng_molecule_t *molecule)
8184 {
8185     int64_t i, n_molecules;
8186
8187     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8188     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8189     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
8190
8191     n_molecules = tng_data->n_molecules;
8192
8193     for(i = n_molecules - 1; i >= 0; i--)
8194     {
8195         *molecule = &tng_data->molecules[i];
8196         if(name[0] == 0 || strcmp(name, (*molecule)->name) == 0)
8197         {
8198             if(nr == -1 || nr == (*molecule)->id)
8199             {
8200                 return(TNG_SUCCESS);
8201             }
8202         }
8203     }
8204
8205     *molecule = 0;
8206
8207     return(TNG_FAILURE);
8208 }
8209
8210 tng_function_status DECLSPECDLLEXPORT tng_molecule_of_index_get
8211                 (tng_trajectory_t tng_data,
8212                  int64_t index,
8213                  tng_molecule_t *molecule)
8214 {
8215     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8216     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
8217
8218     if(index >= tng_data->n_molecules)
8219     {
8220         *molecule = 0;
8221         return(TNG_FAILURE);
8222     }
8223     *molecule = &tng_data->molecules[index];
8224     return(TNG_SUCCESS);
8225 }
8226
8227 tng_function_status DECLSPECDLLEXPORT tng_molecule_system_copy(tng_trajectory_t tng_data_src,
8228                                                                tng_trajectory_t tng_data_dest)
8229 {
8230     tng_molecule_t molecule, molecule_temp;
8231     tng_chain_t chain, chain_temp;
8232     tng_residue_t residue, residue_temp;
8233     tng_atom_t atom, atom_temp;
8234     tng_bond_t bond_temp;
8235     tng_function_status stat;
8236     int64_t i, j, k, l, *list_temp;
8237
8238     TNG_ASSERT(tng_data_src, "TNG library: Trajectory container not properly setup.");
8239     TNG_ASSERT(tng_data_dest, "TNG library: Trajectory container not properly setup.");
8240
8241     for(i = 0; i < tng_data_dest->n_molecules; i++)
8242     {
8243         molecule = &tng_data_dest->molecules[i];
8244         tng_molecule_destroy(tng_data_dest, molecule);
8245     }
8246
8247     tng_data_dest->n_molecules = 0;
8248     tng_data_dest->n_particles = 0;
8249
8250     molecule_temp = realloc(tng_data_dest->molecules,
8251                     sizeof(struct tng_molecule) * tng_data_src->n_molecules);
8252     if(!molecule_temp)
8253     {
8254         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8255                sizeof(struct tng_molecule) * tng_data_src->n_molecules,
8256                __FILE__, __LINE__);
8257         free(tng_data_dest->molecules);
8258         tng_data_dest->molecules = 0;
8259         return(TNG_CRITICAL);
8260     }
8261     list_temp = realloc(tng_data_dest->molecule_cnt_list,
8262                                      sizeof(int64_t) * tng_data_src->n_molecules);
8263     if(!list_temp)
8264     {
8265         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8266                sizeof(int64_t) * tng_data_src->n_molecules,
8267                __FILE__, __LINE__);
8268         free(tng_data_dest->molecule_cnt_list);
8269         tng_data_dest->molecule_cnt_list = 0;
8270         free(molecule_temp);
8271         return(TNG_CRITICAL);
8272     }
8273
8274     tng_data_dest->molecules = molecule_temp;
8275     tng_data_dest->molecule_cnt_list = list_temp;
8276
8277     for(i = 0; i < tng_data_src->n_molecules; i++)
8278     {
8279         molecule = &tng_data_src->molecules[i];
8280         stat = tng_molecule_w_id_add(tng_data_dest, molecule->name, molecule->id,
8281                                      &molecule_temp);
8282         if(stat != TNG_SUCCESS)
8283         {
8284             fprintf(stderr, "TNG library: Cannot create new molecule to make a copy. %s: %d\n",
8285                    __FILE__, __LINE__);
8286             return(stat);
8287         }
8288         molecule_temp->quaternary_str = molecule->quaternary_str;
8289         for(j = 0; j < molecule->n_chains; j++)
8290         {
8291             chain = &molecule->chains[j];
8292             stat = tng_molecule_chain_w_id_add(tng_data_dest, molecule_temp,
8293                                                chain->name, chain->id,
8294                                                &chain_temp);
8295             if(stat != TNG_SUCCESS)
8296             {
8297                 fprintf(stderr, "TNG library: Cannot create new chain to make a copy. %s: %d\n",
8298                        __FILE__, __LINE__);
8299                 return(stat);
8300             }
8301             for(k = 0; k < chain->n_residues; k++)
8302             {
8303                 residue = &chain->residues[k];
8304                 stat = tng_chain_residue_w_id_add(tng_data_dest, chain_temp,
8305                                                   residue->name, residue->id,
8306                                                   &residue_temp);
8307                 if(stat != TNG_SUCCESS)
8308                 {
8309                     fprintf(stderr, "TNG library: Cannot create new residue to make a copy. %s: %d\n",
8310                            __FILE__, __LINE__);
8311                     return(stat);
8312                 }
8313                 for(l = 0; l < residue->n_atoms; l++)
8314                 {
8315                     atom = &molecule->atoms[residue->atoms_offset + l];
8316                     stat = tng_residue_atom_w_id_add(tng_data_dest, residue_temp,
8317                                                      atom->name, atom->atom_type,
8318                                                      atom->id, &atom_temp);
8319                     if(stat != TNG_SUCCESS)
8320                     {
8321                     fprintf(stderr, "TNG library: Cannot create new atom to make a copy. %s: %d\n",
8322                            __FILE__, __LINE__);
8323                         return(stat);
8324                     }
8325                 }
8326             }
8327         }
8328         molecule_temp->n_bonds = molecule->n_bonds;
8329         bond_temp = realloc(molecule_temp->bonds, sizeof(struct tng_bond) *
8330                             molecule->n_bonds);
8331         if(!bond_temp)
8332         {
8333             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8334                    sizeof(struct tng_bond) * molecule->n_bonds,
8335                    __FILE__, __LINE__);
8336             free(molecule_temp->bonds);
8337             molecule_temp->n_bonds = 0;
8338             return(TNG_CRITICAL);
8339         }
8340         molecule_temp->bonds = bond_temp;
8341         for(j = 0; j < molecule->n_bonds; j++)
8342         {
8343             molecule_temp->bonds[j] = molecule->bonds[j];
8344         }
8345         stat = tng_molecule_cnt_set(tng_data_dest, molecule_temp,
8346                                     tng_data_src->molecule_cnt_list[i]);
8347         if(stat != TNG_SUCCESS)
8348         {
8349             fprintf(stderr, "TNG library: Cannot set molecule count. %s: %d.\n",
8350                    __FILE__, __LINE__);
8351             return(stat);
8352         }
8353     }
8354     return(TNG_SUCCESS);
8355 }
8356
8357 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_chains_get
8358                 (const tng_trajectory_t tng_data,
8359                  const tng_molecule_t molecule,
8360                  int64_t *n)
8361 {
8362     (void) tng_data;
8363     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
8364     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8365
8366     *n = molecule->n_chains;
8367
8368     return(TNG_SUCCESS);
8369 }
8370
8371 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_of_index_get
8372                 (tng_trajectory_t tng_data,
8373                  tng_molecule_t molecule,
8374                  int64_t index,
8375                  tng_chain_t *chain)
8376 {
8377     (void) tng_data;
8378     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
8379     TNG_ASSERT(chain, "TNG library: chain must not be a NULL pointer.");
8380
8381     if(index >= molecule->n_chains)
8382     {
8383         *chain = 0;
8384         return(TNG_FAILURE);
8385     }
8386     *chain = &molecule->chains[index];
8387     return(TNG_SUCCESS);
8388 }
8389
8390 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_residues_get
8391                 (const tng_trajectory_t tng_data,
8392                  const tng_molecule_t molecule,
8393                  int64_t *n)
8394 {
8395     (void) tng_data;
8396     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
8397     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8398
8399     *n = molecule->n_residues;
8400
8401     return(TNG_SUCCESS);
8402 }
8403
8404 tng_function_status DECLSPECDLLEXPORT tng_molecule_residue_of_index_get
8405                 (const tng_trajectory_t tng_data,
8406                  const tng_molecule_t molecule,
8407                  const int64_t index,
8408                  tng_residue_t *residue)
8409 {
8410     (void) tng_data;
8411     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
8412     TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
8413
8414     if(index >= molecule->n_residues)
8415     {
8416         *residue = 0;
8417         return(TNG_FAILURE);
8418     }
8419     *residue = &molecule->residues[index];
8420     return(TNG_SUCCESS);
8421 }
8422
8423 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_atoms_get
8424                 (const tng_trajectory_t tng_data,
8425                  const tng_molecule_t molecule,
8426                  int64_t *n)
8427 {
8428     (void) tng_data;
8429     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
8430     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8431
8432     *n = molecule->n_atoms;
8433
8434     return(TNG_SUCCESS);
8435 }
8436
8437 tng_function_status DECLSPECDLLEXPORT tng_molecule_atom_of_index_get
8438                 (const tng_trajectory_t tng_data,
8439                  const tng_molecule_t molecule,
8440                  const int64_t index,
8441                  tng_atom_t *atom)
8442 {
8443     (void) tng_data;
8444     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
8445     TNG_ASSERT(atom, "TNG library: atom must not be a NULL pointer.");
8446
8447     if(index >= molecule->n_atoms)
8448     {
8449         *atom = 0;
8450         return(TNG_FAILURE);
8451     }
8452     *atom = &molecule->atoms[index];
8453     return(TNG_SUCCESS);
8454 }
8455
8456 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_find
8457                 (tng_trajectory_t tng_data,
8458                  tng_molecule_t molecule,
8459                  const char *name,
8460                  int64_t nr,
8461                  tng_chain_t *chain)
8462 {
8463     int64_t i, n_chains;
8464     (void)tng_data;
8465
8466     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8467     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8468
8469     n_chains = molecule->n_chains;
8470
8471     for(i = n_chains - 1; i >= 0; i--)
8472     {
8473         *chain = &molecule->chains[i];
8474         if(name[0] == 0 || strcmp(name, (*chain)->name) == 0)
8475         {
8476             if(nr == -1 || nr == (*chain)->id)
8477             {
8478                 return(TNG_SUCCESS);
8479             }
8480         }
8481     }
8482
8483     *chain = 0;
8484
8485     return(TNG_FAILURE);
8486 }
8487
8488 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_add
8489                 (tng_trajectory_t tng_data,
8490                  tng_molecule_t molecule,
8491                  const char *name,
8492                  tng_chain_t *chain)
8493 {
8494     int64_t id;
8495
8496     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8497     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8498
8499     /* Set ID to the ID of the last chain + 1 */
8500     if(molecule->n_chains)
8501     {
8502         id = molecule->chains[molecule->n_chains-1].id + 1;
8503     }
8504     else
8505     {
8506         id = 1;
8507     }
8508
8509     return(tng_molecule_chain_w_id_add(tng_data, molecule, name,
8510                                        id, chain));
8511 }
8512
8513 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_w_id_add
8514                 (tng_trajectory_t tng_data,
8515                  tng_molecule_t molecule,
8516                  const char *name,
8517                  const int64_t id,
8518                  tng_chain_t *chain)
8519 {
8520     tng_chain_t new_chains;
8521     tng_function_status stat = TNG_SUCCESS;
8522
8523     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8524     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8525
8526     new_chains = realloc(molecule->chains,
8527                          sizeof(struct tng_chain) *
8528                          (molecule->n_chains + 1));
8529
8530     if(!new_chains)
8531     {
8532         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8533                sizeof(struct tng_chain) * (molecule->n_chains + 1),
8534                __FILE__, __LINE__);
8535         free(molecule->chains);
8536         molecule->chains = 0;
8537         return(TNG_CRITICAL);
8538     }
8539
8540     molecule->chains = new_chains;
8541
8542     *chain = &new_chains[molecule->n_chains];
8543     (*chain)->name = 0;
8544
8545     tng_chain_name_set(tng_data, *chain, name);
8546
8547     (*chain)->molecule = molecule;
8548     (*chain)->n_residues = 0;
8549
8550     molecule->n_chains++;
8551
8552     (*chain)->id = id;
8553
8554     return(stat);
8555 }
8556
8557 tng_function_status DECLSPECDLLEXPORT tng_molecule_bond_add
8558                 (const tng_trajectory_t tng_data,
8559                  tng_molecule_t molecule,
8560                  const int64_t from_atom_id,
8561                  const int64_t to_atom_id,
8562                  tng_bond_t *bond)
8563 {
8564     tng_bond_t new_bonds;
8565     (void)tng_data;
8566
8567     new_bonds = realloc(molecule->bonds,
8568                         sizeof(struct tng_bond) *
8569                         (molecule->n_bonds + 1));
8570
8571     if(!new_bonds)
8572     {
8573         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8574                sizeof(struct tng_bond) * (molecule->n_bonds + 1),
8575                __FILE__, __LINE__);
8576         *bond = 0;
8577         free(molecule->bonds);
8578         molecule->bonds = 0;
8579         return(TNG_CRITICAL);
8580     }
8581
8582     molecule->bonds = new_bonds;
8583
8584     *bond = &new_bonds[molecule->n_bonds];
8585
8586     (*bond)->from_atom_id = from_atom_id;
8587     (*bond)->to_atom_id = to_atom_id;
8588
8589     molecule->n_bonds++;
8590
8591     return(TNG_SUCCESS);
8592 }
8593
8594 tng_function_status DECLSPECDLLEXPORT tng_molecule_atom_find
8595                 (tng_trajectory_t tng_data,
8596                  tng_molecule_t molecule,
8597                  const char *name,
8598                  int64_t id,
8599                  tng_atom_t *atom)
8600 {
8601     int64_t i, n_atoms;
8602     (void)tng_data;
8603
8604     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8605
8606     n_atoms = molecule->n_atoms;
8607
8608     for(i = n_atoms - 1; i >= 0; i--)
8609     {
8610         *atom = &molecule->atoms[i];
8611         if(name[0] == 0 || strcmp(name, (*atom)->name) == 0)
8612         {
8613             if(id == -1 || id == (*atom)->id)
8614             {
8615                 return(TNG_SUCCESS);
8616             }
8617         }
8618     }
8619
8620     *atom = 0;
8621
8622     return(TNG_FAILURE);
8623 }
8624
8625 tng_function_status tng_chain_name_get(const tng_trajectory_t tng_data,
8626                                        const tng_chain_t chain,
8627                                        char *name,
8628                                        const int max_len)
8629 {
8630     (void) tng_data;
8631     TNG_ASSERT(chain, "TNG library: chain must not be NULL");
8632     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
8633
8634     strncpy(name, chain->name, max_len - 1);
8635     name[max_len - 1] = 0;
8636
8637     if(strlen(chain->name) > (unsigned int)max_len - 1)
8638     {
8639         return(TNG_FAILURE);
8640     }
8641     return(TNG_SUCCESS);
8642 }
8643
8644 tng_function_status DECLSPECDLLEXPORT tng_chain_name_set
8645                 (tng_trajectory_t tng_data,
8646                  tng_chain_t chain,
8647                  const char *new_name)
8648 {
8649     unsigned int len;
8650     (void)tng_data;
8651
8652     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
8653
8654     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
8655
8656     /* If the currently stored string length is not enough to store the new
8657      * string it is freed and reallocated. */
8658     if(chain->name && strlen(chain->name) < len)
8659     {
8660         free(chain->name);
8661         chain->name = 0;
8662     }
8663     if(!chain->name)
8664     {
8665         chain->name = malloc(len);
8666         if(!chain->name)
8667         {
8668             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
8669                    __FILE__, __LINE__);
8670             return(TNG_CRITICAL);
8671         }
8672     }
8673
8674     strncpy(chain->name, new_name, len);
8675
8676     return(TNG_SUCCESS);
8677 }
8678
8679 tng_function_status DECLSPECDLLEXPORT tng_chain_num_residues_get
8680                 (const tng_trajectory_t tng_data,
8681                  const tng_chain_t chain,
8682                  int64_t *n)
8683 {
8684     (void) tng_data;
8685     TNG_ASSERT(chain, "TNG library: chain must not be NULL");
8686     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8687
8688     *n = chain->n_residues;
8689
8690     return(TNG_SUCCESS);
8691 }
8692
8693 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_of_index_get
8694                 (const tng_trajectory_t tng_data,
8695                  const tng_chain_t chain,
8696                  const int64_t index,
8697                  tng_residue_t *residue)
8698 {
8699     (void) tng_data;
8700     TNG_ASSERT(chain, "TNG library: chain must not be a NULL pointer.");
8701     TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
8702
8703     if(index >= chain->n_residues)
8704     {
8705         *residue = 0;
8706         return(TNG_FAILURE);
8707     }
8708     *residue = &chain->residues[index];
8709     return(TNG_SUCCESS);
8710 }
8711
8712 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_find
8713                 (tng_trajectory_t tng_data,
8714                  tng_chain_t chain,
8715                  const char *name,
8716                  int64_t id,
8717                  tng_residue_t *residue)
8718 {
8719     int64_t i, n_residues;
8720     (void)tng_data;
8721
8722     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8723
8724     n_residues = chain->n_residues;
8725
8726     for(i = n_residues - 1; i >= 0; i--)
8727     {
8728         *residue = &chain->residues[i];
8729         if(name[0] == 0 || strcmp(name, (*residue)->name) == 0)
8730         {
8731             if(id == -1 || id == (*residue)->id)
8732             {
8733                 return(TNG_SUCCESS);
8734             }
8735         }
8736     }
8737
8738     *residue = 0;
8739
8740     return(TNG_FAILURE);
8741 }
8742
8743 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_add
8744                 (tng_trajectory_t tng_data,
8745                  tng_chain_t chain,
8746                  const char *name,
8747                  tng_residue_t *residue)
8748 {
8749     int64_t id;
8750
8751     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8752     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8753
8754     /* Set ID to the ID of the last residue + 1 */
8755     if(chain->n_residues)
8756     {
8757         id = chain->residues[chain->n_residues-1].id + 1;
8758     }
8759     else
8760     {
8761         id = 0;
8762     }
8763
8764     return(tng_chain_residue_w_id_add(tng_data, chain, name,
8765                                       id, residue));
8766 }
8767
8768 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_w_id_add
8769                 (tng_trajectory_t tng_data,
8770                  tng_chain_t chain,
8771                  const char *name,
8772                  const int64_t id,
8773                  tng_residue_t *residue)
8774 {
8775     int64_t curr_index;
8776     tng_residue_t new_residues, temp_residue, last_residue;
8777     tng_molecule_t molecule = chain->molecule;
8778     tng_function_status stat = TNG_SUCCESS;
8779
8780     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8781     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8782
8783     if(chain->n_residues)
8784     {
8785         curr_index = chain->residues - molecule->residues;
8786     }
8787     else
8788     {
8789         curr_index = -1;
8790     }
8791
8792     new_residues = realloc(molecule->residues,
8793                            sizeof(struct tng_residue) *
8794                            (molecule->n_residues + 1));
8795
8796     if(!new_residues)
8797     {
8798         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8799                sizeof(struct tng_residue) * (molecule->n_residues + 1),
8800                __FILE__, __LINE__);
8801         free(molecule->residues);
8802         molecule->residues = 0;
8803         return(TNG_CRITICAL);
8804     }
8805
8806     molecule->residues = new_residues;
8807
8808     if(curr_index != -1)
8809     {
8810         chain->residues = new_residues + curr_index;
8811         if(molecule->n_residues)
8812         {
8813             last_residue = &new_residues[molecule->n_residues - 1];
8814
8815             temp_residue = chain->residues + (chain->n_residues - 1);
8816             /* Make space in list of residues to add the new residues together with the other
8817             * residues of this chain */
8818             if(temp_residue != last_residue)
8819             {
8820                 ++temp_residue;
8821                 memmove(temp_residue + 1, temp_residue,
8822                         last_residue - temp_residue);
8823             }
8824         }
8825     }
8826     else
8827     {
8828         curr_index = molecule->n_residues;
8829     }
8830
8831     *residue = &molecule->residues[curr_index + chain->n_residues];
8832
8833     if(!chain->n_residues)
8834     {
8835         chain->residues = *residue;
8836     }
8837     else
8838     {
8839         chain->residues = &molecule->residues[curr_index];
8840     }
8841
8842     (*residue)->name = 0;
8843     tng_residue_name_set(tng_data, *residue, name);
8844
8845     (*residue)->chain = chain;
8846     (*residue)->n_atoms = 0;
8847     (*residue)->atoms_offset = 0;
8848
8849     chain->n_residues++;
8850     molecule->n_residues++;
8851
8852     (*residue)->id = id;
8853
8854     return(stat);
8855 }
8856
8857 tng_function_status tng_residue_name_get(const tng_trajectory_t tng_data,
8858                                          const tng_residue_t residue,
8859                                          char *name,
8860                                          const int max_len)
8861 {
8862     (void) tng_data;
8863     TNG_ASSERT(residue, "TNG library: residue must not be NULL");
8864     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
8865
8866     strncpy(name, residue->name, max_len - 1);
8867     name[max_len - 1] = 0;
8868
8869     if(strlen(residue->name) > (unsigned int)max_len - 1)
8870     {
8871         return(TNG_FAILURE);
8872     }
8873     return(TNG_SUCCESS);
8874 }
8875
8876 tng_function_status DECLSPECDLLEXPORT tng_residue_name_set(tng_trajectory_t tng_data,
8877                                                            tng_residue_t residue,
8878                                                            const char *new_name)
8879 {
8880     unsigned int len;
8881     (void)tng_data;
8882
8883     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8884     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
8885
8886     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
8887
8888     /* If the currently stored string length is not enough to store the new
8889      * string it is freed and reallocated. */
8890     if(residue->name && strlen(residue->name) < len)
8891     {
8892         free(residue->name);
8893         residue->name = 0;
8894     }
8895     if(!residue->name)
8896     {
8897         residue->name = malloc(len);
8898         if(!residue->name)
8899         {
8900             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
8901                    __FILE__, __LINE__);
8902             return(TNG_CRITICAL);
8903         }
8904     }
8905
8906     strncpy(residue->name, new_name, len);
8907
8908     return(TNG_SUCCESS);
8909 }
8910
8911 tng_function_status DECLSPECDLLEXPORT tng_residue_num_atoms_get
8912                 (const tng_trajectory_t tng_data,
8913                  const tng_residue_t residue,
8914                  int64_t *n)
8915 {
8916     (void) tng_data;
8917     TNG_ASSERT(residue, "TNG library: residue must not be NULL");
8918     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8919
8920     *n = residue->n_atoms;
8921
8922     return(TNG_SUCCESS);
8923 }
8924
8925 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_of_index_get
8926                 (const tng_trajectory_t tng_data,
8927                  const tng_residue_t residue,
8928                  const int64_t index,
8929                  tng_atom_t *atom)
8930 {
8931     tng_chain_t chain;
8932     tng_molecule_t molecule;
8933
8934     (void) tng_data;
8935     TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
8936     TNG_ASSERT(atom, "TNG library: atom must not be a NULL pointer.");
8937
8938     if(index >= residue->n_atoms)
8939     {
8940         *atom = 0;
8941         return(TNG_FAILURE);
8942     }
8943     chain = residue->chain;
8944     molecule = chain->molecule;
8945
8946     if(index + residue->atoms_offset >= molecule->n_atoms)
8947     {
8948         *atom = 0;
8949         return(TNG_FAILURE);
8950     }
8951
8952     *atom = &molecule->atoms[residue->atoms_offset + index];
8953     return(TNG_SUCCESS);
8954 }
8955
8956 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_add
8957                 (tng_trajectory_t tng_data,
8958                  tng_residue_t residue,
8959                  const char *atom_name,
8960                  const char *atom_type,
8961                  tng_atom_t *atom)
8962 {
8963     int64_t id;
8964
8965     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8966     TNG_ASSERT(atom_name, "TNG library: atom_name must not be a NULL pointer.");
8967     TNG_ASSERT(atom_type, "TNG library: atom_type must not be a NULL pointer.");
8968
8969     /* Set ID to the ID of the last atom + 1 */
8970     if(residue->chain->molecule->n_atoms)
8971     {
8972         id = residue->chain->molecule->atoms[residue->chain->molecule->n_atoms-1].id + 1;
8973     }
8974     else
8975     {
8976         id = 0;
8977     }
8978
8979     return(tng_residue_atom_w_id_add(tng_data, residue, atom_name, atom_type,
8980                                      id, atom));
8981 }
8982
8983 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_w_id_add
8984                 (tng_trajectory_t tng_data,
8985                  tng_residue_t residue,
8986                  const char *atom_name,
8987                  const char *atom_type,
8988                  const int64_t id,
8989                  tng_atom_t *atom)
8990 {
8991     tng_atom_t new_atoms;
8992     tng_molecule_t molecule = residue->chain->molecule;
8993     tng_function_status stat = TNG_SUCCESS;
8994
8995     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8996     TNG_ASSERT(atom_name, "TNG library: atom_name must not be a NULL pointer.");
8997     TNG_ASSERT(atom_type, "TNG library: atom_type must not be a NULL pointer.");
8998
8999     if(!residue->n_atoms)
9000     {
9001         residue->atoms_offset = molecule->n_atoms;
9002     }
9003
9004     new_atoms = realloc(molecule->atoms,
9005                         sizeof(struct tng_atom) *
9006                         (molecule->n_atoms + 1));
9007
9008     if(!new_atoms)
9009     {
9010         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
9011                sizeof(struct tng_atom) * (molecule->n_atoms + 1),
9012                __FILE__, __LINE__);
9013         free(molecule->atoms);
9014         molecule->atoms = 0;
9015         return(TNG_CRITICAL);
9016     }
9017
9018     molecule->atoms = new_atoms;
9019
9020     *atom = &new_atoms[molecule->n_atoms];
9021
9022     tng_atom_init(*atom);
9023     tng_atom_name_set(tng_data, *atom, atom_name);
9024     tng_atom_type_set(tng_data, *atom, atom_type);
9025
9026     (*atom)->residue = residue;
9027
9028     residue->n_atoms++;
9029     molecule->n_atoms++;
9030
9031     (*atom)->id = id;
9032
9033     return(stat);
9034 }
9035
9036 tng_function_status DECLSPECDLLEXPORT tng_molecule_alloc(const tng_trajectory_t tng_data,
9037                                                          tng_molecule_t *molecule_p)
9038 {
9039     *molecule_p = malloc(sizeof(struct tng_molecule));
9040     if(!*molecule_p)
9041     {
9042         fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
9043                sizeof(struct tng_molecule), __FILE__, __LINE__);
9044         return(TNG_CRITICAL);
9045     }
9046
9047     tng_molecule_init(tng_data, *molecule_p);
9048
9049     return(TNG_SUCCESS);
9050 }
9051
9052 tng_function_status DECLSPECDLLEXPORT tng_molecule_free(const tng_trajectory_t tng_data,
9053                                                         tng_molecule_t *molecule_p)
9054 {
9055     if(!*molecule_p)
9056     {
9057         return(TNG_SUCCESS);
9058     }
9059
9060     tng_molecule_destroy(tng_data, *molecule_p);
9061
9062     free(*molecule_p);
9063     *molecule_p = 0;
9064
9065     return(TNG_SUCCESS);
9066 }
9067
9068 tng_function_status DECLSPECDLLEXPORT tng_molecule_init(const tng_trajectory_t tng_data,
9069                                                         tng_molecule_t molecule)
9070 {
9071     (void)tng_data;
9072     molecule->quaternary_str = 1;
9073     molecule->name = 0;
9074     molecule->n_chains = 0;
9075     molecule->chains = 0;
9076     molecule->n_residues = 0;
9077     molecule->residues = 0;
9078     molecule->n_atoms = 0;
9079     molecule->atoms = 0;
9080     molecule->n_bonds = 0;
9081     molecule->bonds = 0;
9082
9083     return(TNG_SUCCESS);
9084 }
9085
9086 tng_function_status DECLSPECDLLEXPORT tng_molecule_destroy(const tng_trajectory_t tng_data,
9087                                                            tng_molecule_t molecule)
9088 {
9089     int64_t i;
9090     (void)tng_data;
9091
9092     if(molecule->name)
9093     {
9094         free(molecule->name);
9095         molecule->name = 0;
9096     }
9097
9098     if(molecule->chains)
9099     {
9100         for(i = 0; i < molecule->n_chains; i++)
9101         {
9102             if(molecule->chains[i].name)
9103             {
9104                 free(molecule->chains[i].name);
9105                 molecule->chains[i].name = 0;
9106             }
9107         }
9108         free(molecule->chains);
9109         molecule->chains = 0;
9110     }
9111     molecule->n_chains = 0;
9112
9113     if(molecule->residues)
9114     {
9115         for(i = 0; i < molecule->n_residues; i++)
9116         {
9117             if(molecule->residues[i].name)
9118             {
9119                 free(molecule->residues[i].name);
9120                 molecule->residues[i].name = 0;
9121             }
9122         }
9123         free(molecule->residues);
9124         molecule->residues = 0;
9125     }
9126     molecule->n_residues = 0;
9127
9128     if(molecule->atoms)
9129     {
9130         for(i = 0; i < molecule->n_atoms; i++)
9131         {
9132             tng_atom_destroy(&molecule->atoms[i]);
9133         }
9134         free(molecule->atoms);
9135         molecule->atoms = 0;
9136     }
9137     molecule->n_atoms = 0;
9138
9139     if(molecule->bonds)
9140     {
9141         free(molecule->bonds);
9142         molecule->bonds = 0;
9143     }
9144     molecule->n_bonds = 0;
9145
9146     return(TNG_SUCCESS);
9147 }
9148
9149 tng_function_status DECLSPECDLLEXPORT tng_molecule_name_of_particle_nr_get
9150                 (const tng_trajectory_t tng_data,
9151                  const int64_t nr,
9152                  char *name,
9153                  int max_len)
9154 {
9155     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9156     tng_molecule_t mol;
9157     tng_bool found = TNG_FALSE;
9158
9159     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9160     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
9161
9162     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9163
9164     if(!molecule_cnt_list)
9165     {
9166         return(TNG_FAILURE);
9167     }
9168
9169     for(i = 0; i < tng_data->n_molecules; i++)
9170     {
9171         mol = &tng_data->molecules[i];
9172         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9173         {
9174             cnt += mol->n_atoms * molecule_cnt_list[i];
9175             continue;
9176         }
9177         found = TNG_TRUE;
9178         break;
9179     }
9180     if(!found)
9181     {
9182         return(TNG_FAILURE);
9183     }
9184
9185     strncpy(name, mol->name, max_len - 1);
9186     name[max_len - 1] = 0;
9187
9188     if(strlen(mol->name) > (unsigned int)max_len - 1)
9189     {
9190         return(TNG_FAILURE);
9191     }
9192     return(TNG_SUCCESS);
9193 }
9194
9195 tng_function_status DECLSPECDLLEXPORT tng_molecule_id_of_particle_nr_get
9196                 (const tng_trajectory_t tng_data,
9197                  const int64_t nr,
9198                  int64_t *id)
9199 {
9200     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9201     tng_molecule_t mol;
9202     tng_bool found = TNG_FALSE;
9203
9204     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9205     TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
9206
9207     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9208
9209     if(!molecule_cnt_list)
9210     {
9211         return(TNG_FAILURE);
9212     }
9213
9214     for(i = 0; i < tng_data->n_molecules; i++)
9215     {
9216         mol = &tng_data->molecules[i];
9217         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9218         {
9219             cnt += mol->n_atoms * molecule_cnt_list[i];
9220             continue;
9221         }
9222         found = TNG_TRUE;
9223         break;
9224     }
9225     if(!found)
9226     {
9227         return(TNG_FAILURE);
9228     }
9229
9230     *id = mol->id;
9231
9232     return(TNG_SUCCESS);
9233 }
9234
9235 tng_function_status DECLSPECDLLEXPORT tng_molsystem_bonds_get
9236                 (const tng_trajectory_t tng_data,
9237                  int64_t *n_bonds,
9238                  int64_t **from_atoms,
9239                  int64_t **to_atoms)
9240 {
9241     int64_t atom_cnt = 0, cnt, mol_cnt, i, j, k;
9242     int64_t from_atom, to_atom, *molecule_cnt_list = 0;
9243     tng_molecule_t mol;
9244     tng_bond_t bond;
9245
9246     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9247     TNG_ASSERT(n_bonds, "TNG library: n_bonds must not be a NULL pointer.");
9248     TNG_ASSERT(from_atoms, "TNG library: from_atoms must not be a NULL pointer.");
9249     TNG_ASSERT(to_atoms, "TNG library: to_atoms must not be a NULL pointer.");
9250
9251     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9252
9253     if(!molecule_cnt_list)
9254     {
9255         return(TNG_FAILURE);
9256     }
9257
9258     *n_bonds = 0;
9259     /* First count the total number of bonds to allocate memory */
9260     for(i = 0; i < tng_data->n_molecules; i++)
9261     {
9262         mol = &tng_data->molecules[i];
9263         mol_cnt = molecule_cnt_list[i];
9264         *n_bonds += mol_cnt * mol->n_bonds;
9265     }
9266     if(*n_bonds == 0)
9267     {
9268         return(TNG_SUCCESS);
9269     }
9270
9271     *from_atoms = malloc(sizeof(int64_t) * (*n_bonds));
9272     if(!*from_atoms)
9273     {
9274         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
9275                sizeof(int64_t) * (*n_bonds), __FILE__, __LINE__);
9276         return(TNG_CRITICAL);
9277     }
9278     *to_atoms = malloc(sizeof(int64_t) * (*n_bonds));
9279     if(!*to_atoms)
9280     {
9281         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
9282                sizeof(int64_t) * (*n_bonds), __FILE__, __LINE__);
9283         free(*from_atoms);
9284         *from_atoms = 0;
9285         return(TNG_CRITICAL);
9286     }
9287
9288     cnt = 0;
9289     for(i = 0; i < tng_data->n_molecules; i++)
9290     {
9291         mol = &tng_data->molecules[i];
9292         mol_cnt = molecule_cnt_list[i];
9293         for(j = 0; j < mol_cnt; j++)
9294         {
9295             for(k = 0; k < mol->n_bonds; k++)
9296             {
9297                 bond = &mol->bonds[k];
9298                 from_atom = atom_cnt + bond->from_atom_id;
9299                 to_atom = atom_cnt + bond->to_atom_id;
9300                 (*from_atoms)[cnt] = from_atom;
9301                 (*to_atoms)[cnt++] = to_atom;
9302             }
9303             atom_cnt += mol->n_atoms;
9304         }
9305     }
9306
9307     return(TNG_SUCCESS);
9308 }
9309
9310 tng_function_status DECLSPECDLLEXPORT tng_chain_name_of_particle_nr_get
9311                 (const tng_trajectory_t tng_data,
9312                  const int64_t nr,
9313                  char *name,
9314                  int max_len)
9315 {
9316     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9317     tng_molecule_t mol;
9318     tng_atom_t atom;
9319     tng_bool found = TNG_FALSE;
9320
9321     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9322     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
9323
9324     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9325
9326     if(!molecule_cnt_list)
9327     {
9328         return(TNG_FAILURE);
9329     }
9330
9331     for(i = 0; i < tng_data->n_molecules; i++)
9332     {
9333         mol = &tng_data->molecules[i];
9334         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9335         {
9336             cnt += mol->n_atoms * molecule_cnt_list[i];
9337             continue;
9338         }
9339         atom = &mol->atoms[nr % mol->n_atoms];
9340         found = TNG_TRUE;
9341         break;
9342     }
9343     if(!found)
9344     {
9345         return(TNG_FAILURE);
9346     }
9347     if(!atom->residue || !atom->residue->chain)
9348     {
9349         return(TNG_FAILURE);
9350     }
9351
9352     strncpy(name, atom->residue->chain->name, max_len - 1);
9353     name[max_len - 1] = 0;
9354
9355     if(strlen(atom->residue->chain->name) > (unsigned int)max_len - 1)
9356     {
9357         return(TNG_FAILURE);
9358     }
9359     return(TNG_SUCCESS);
9360 }
9361
9362 tng_function_status DECLSPECDLLEXPORT tng_residue_name_of_particle_nr_get
9363                 (const tng_trajectory_t tng_data,
9364                  const int64_t nr,
9365                  char *name,
9366                  int max_len)
9367 {
9368     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9369     tng_molecule_t mol;
9370     tng_atom_t atom;
9371     tng_bool found = TNG_FALSE;
9372
9373     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9374     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
9375
9376     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9377
9378     if(!molecule_cnt_list)
9379     {
9380         return(TNG_FAILURE);
9381     }
9382
9383     for(i = 0; i < tng_data->n_molecules; i++)
9384     {
9385         mol = &tng_data->molecules[i];
9386         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9387         {
9388             cnt += mol->n_atoms * molecule_cnt_list[i];
9389             continue;
9390         }
9391         atom = &mol->atoms[nr % mol->n_atoms];
9392         found = TNG_TRUE;
9393         break;
9394     }
9395     if(!found)
9396     {
9397         return(TNG_FAILURE);
9398     }
9399     if(!atom->residue)
9400     {
9401         return(TNG_FAILURE);
9402     }
9403
9404     strncpy(name, atom->residue->name, max_len - 1);
9405     name[max_len - 1] = 0;
9406
9407     if(strlen(atom->residue->name) > (unsigned int)max_len - 1)
9408     {
9409         return(TNG_FAILURE);
9410     }
9411     return(TNG_SUCCESS);
9412 }
9413
9414 tng_function_status DECLSPECDLLEXPORT tng_residue_id_of_particle_nr_get
9415                 (const tng_trajectory_t tng_data,
9416                  const int64_t nr,
9417                  int64_t *id)
9418 {
9419     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9420     tng_molecule_t mol;
9421     tng_atom_t atom;
9422     tng_bool found = TNG_FALSE;
9423
9424     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9425     TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
9426
9427     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9428
9429     if(!molecule_cnt_list)
9430     {
9431         return(TNG_FAILURE);
9432     }
9433
9434     for(i = 0; i < tng_data->n_molecules; i++)
9435     {
9436         mol = &tng_data->molecules[i];
9437         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9438         {
9439             cnt += mol->n_atoms * molecule_cnt_list[i];
9440             continue;
9441         }
9442         atom = &mol->atoms[nr % mol->n_atoms];
9443         found = TNG_TRUE;
9444         break;
9445     }
9446     if(!found)
9447     {
9448         return(TNG_FAILURE);
9449     }
9450     if(!atom->residue)
9451     {
9452         return(TNG_FAILURE);
9453     }
9454
9455     *id = atom->residue->id;
9456
9457     return(TNG_SUCCESS);
9458 }
9459
9460 tng_function_status DECLSPECDLLEXPORT tng_global_residue_id_of_particle_nr_get
9461                 (const tng_trajectory_t tng_data,
9462                  const int64_t nr,
9463                  int64_t *id)
9464 {
9465     int64_t cnt = 0, i, offset = 0, *molecule_cnt_list = 0;
9466     tng_molecule_t mol;
9467     tng_atom_t atom;
9468     tng_bool found = TNG_FALSE;
9469
9470     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9471     TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
9472
9473     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9474
9475     if(!molecule_cnt_list)
9476     {
9477         return(TNG_FAILURE);
9478     }
9479
9480     for(i = 0; i < tng_data->n_molecules; i++)
9481     {
9482         mol = &tng_data->molecules[i];
9483         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9484         {
9485             cnt += mol->n_atoms * molecule_cnt_list[i];
9486             offset += mol->n_residues * molecule_cnt_list[i];
9487             continue;
9488         }
9489         atom = &mol->atoms[nr % mol->n_atoms];
9490         found = TNG_TRUE;
9491         break;
9492     }
9493     if(!found)
9494     {
9495         return(TNG_FAILURE);
9496     }
9497     if(!atom->residue)
9498     {
9499         return(TNG_FAILURE);
9500     }
9501
9502     offset += mol->n_residues * ((nr - cnt) / mol->n_atoms);
9503
9504     *id = atom->residue->id + offset;
9505
9506     return(TNG_SUCCESS);
9507 }
9508
9509 tng_function_status DECLSPECDLLEXPORT tng_atom_name_of_particle_nr_get
9510                 (const tng_trajectory_t tng_data,
9511                  const int64_t nr,
9512                  char *name,
9513                  int max_len)
9514 {
9515     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9516     tng_molecule_t mol;
9517     tng_atom_t atom;
9518     tng_bool found = TNG_FALSE;
9519
9520     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9521     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
9522
9523     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9524
9525     if(!molecule_cnt_list)
9526     {
9527         return(TNG_FAILURE);
9528     }
9529
9530     for(i = 0; i < tng_data->n_molecules; i++)
9531     {
9532         mol = &tng_data->molecules[i];
9533         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9534         {
9535             cnt += mol->n_atoms * molecule_cnt_list[i];
9536             continue;
9537         }
9538         atom = &mol->atoms[nr % mol->n_atoms];
9539         found = TNG_TRUE;
9540         break;
9541     }
9542     if(!found)
9543     {
9544         return(TNG_FAILURE);
9545     }
9546
9547     strncpy(name, atom->name, max_len - 1);
9548     name[max_len - 1] = 0;
9549
9550     if(strlen(atom->name) > (unsigned int)max_len - 1)
9551     {
9552         return(TNG_FAILURE);
9553     }
9554     return(TNG_SUCCESS);
9555 }
9556
9557 tng_function_status tng_atom_type_of_particle_nr_get
9558                 (const tng_trajectory_t tng_data,
9559                  const int64_t nr,
9560                  char *type,
9561                  int max_len)
9562 {
9563     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9564     tng_molecule_t mol;
9565     tng_atom_t atom;
9566     tng_bool found = TNG_FALSE;
9567
9568     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9569     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
9570
9571     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9572
9573     if(!molecule_cnt_list)
9574     {
9575         return(TNG_FAILURE);
9576     }
9577
9578     for(i = 0; i < tng_data->n_molecules; i++)
9579     {
9580         mol = &tng_data->molecules[i];
9581         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9582         {
9583             cnt += mol->n_atoms * molecule_cnt_list[i];
9584             continue;
9585         }
9586         atom = &mol->atoms[nr % mol->n_atoms];
9587         found = TNG_TRUE;
9588         break;
9589     }
9590     if(!found)
9591     {
9592         return(TNG_FAILURE);
9593     }
9594
9595     strncpy(type, atom->atom_type, max_len - 1);
9596     type[max_len - 1] = 0;
9597
9598     if(strlen(atom->atom_type) > (unsigned int)max_len - 1)
9599     {
9600         return(TNG_FAILURE);
9601     }
9602     return(TNG_SUCCESS);
9603 }
9604
9605 tng_function_status DECLSPECDLLEXPORT tng_particle_mapping_add
9606                 (tng_trajectory_t tng_data,
9607                  const int64_t num_first_particle,
9608                  const int64_t n_particles,
9609                  const int64_t *mapping_table)
9610 {
9611     int64_t i;
9612     tng_particle_mapping_t mapping;
9613     tng_trajectory_frame_set_t frame_set;
9614
9615     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9616
9617     frame_set = &tng_data->current_trajectory_frame_set;
9618
9619     /* Sanity check of the particle ranges. Split into multiple if
9620      * statements for improved readability */
9621     for(i = 0; i < frame_set->n_mapping_blocks; i++)
9622     {
9623         mapping = &frame_set->mappings[i];
9624         if(num_first_particle >= mapping->num_first_particle &&
9625            num_first_particle < mapping->num_first_particle +
9626                                    mapping->n_particles)
9627         {
9628             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
9629             return(TNG_FAILURE);
9630         }
9631         if(num_first_particle + n_particles >=
9632            mapping->num_first_particle &&
9633            num_first_particle + n_particles <
9634            mapping->num_first_particle + mapping->n_particles)
9635         {
9636             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
9637             return(TNG_FAILURE);
9638         }
9639         if(mapping->num_first_particle >= num_first_particle &&
9640            mapping->num_first_particle < num_first_particle +
9641                                             n_particles)
9642         {
9643             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
9644             return(TNG_FAILURE);
9645         }
9646         if(mapping->num_first_particle + mapping->n_particles >
9647            num_first_particle &&
9648            mapping->num_first_particle + mapping->n_particles <
9649            num_first_particle + n_particles)
9650         {
9651             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
9652             return(TNG_FAILURE);
9653         }
9654     }
9655
9656     frame_set->n_mapping_blocks++;
9657
9658     mapping = realloc(frame_set->mappings, sizeof(struct tng_particle_mapping) *
9659                       frame_set->n_mapping_blocks);
9660
9661     if(!mapping)
9662     {
9663         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
9664                sizeof(struct tng_particle_mapping)*frame_set->n_mapping_blocks,
9665                __FILE__, __LINE__);
9666         free(frame_set->mappings);
9667         frame_set->mappings = 0;
9668         return(TNG_CRITICAL);
9669     }
9670     frame_set->mappings = mapping;
9671
9672     frame_set->mappings[frame_set->n_mapping_blocks - 1].num_first_particle = num_first_particle;
9673     frame_set->mappings[frame_set->n_mapping_blocks - 1].n_particles = n_particles;
9674
9675     frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers = malloc(sizeof(int64_t) * n_particles);
9676     if(!frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers)
9677     {
9678         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
9679                sizeof(int64_t) * n_particles, __FILE__, __LINE__);
9680         return(TNG_CRITICAL);
9681     }
9682
9683     for(i=0; i<n_particles; i++)
9684     {
9685         frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers[i] = mapping_table[i];
9686     }
9687
9688     return(TNG_SUCCESS);
9689 }
9690
9691 tng_function_status DECLSPECDLLEXPORT tng_frame_set_particle_mapping_free(tng_trajectory_t tng_data)
9692 {
9693     tng_trajectory_frame_set_t frame_set;
9694     tng_particle_mapping_t mapping;
9695     int64_t i;
9696
9697     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9698
9699     frame_set = &tng_data->current_trajectory_frame_set;
9700
9701     if(frame_set->n_mapping_blocks && frame_set->mappings)
9702     {
9703         for(i = 0; i < frame_set->n_mapping_blocks; i++)
9704         {
9705             mapping = &frame_set->mappings[i];
9706             if(mapping->real_particle_numbers)
9707             {
9708                 free(mapping->real_particle_numbers);
9709                 mapping->real_particle_numbers = 0;
9710             }
9711         }
9712         free(frame_set->mappings);
9713         frame_set->mappings = 0;
9714         frame_set->n_mapping_blocks = 0;
9715     }
9716
9717     return(TNG_SUCCESS);
9718 }
9719
9720 tng_function_status DECLSPECDLLEXPORT tng_trajectory_init(tng_trajectory_t *tng_data_p)
9721 {
9722     time_t seconds;
9723     tng_trajectory_frame_set_t frame_set;
9724     tng_trajectory_t tng_data;
9725
9726     *tng_data_p = malloc(sizeof(struct tng_trajectory));
9727     if(!*tng_data_p)
9728     {
9729         fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
9730                sizeof(struct tng_trajectory), __FILE__, __LINE__);
9731         return(TNG_CRITICAL);
9732     }
9733
9734     tng_data = *tng_data_p;
9735
9736     frame_set = &tng_data->current_trajectory_frame_set;
9737
9738     tng_data->input_file_path = 0;
9739     tng_data->input_file = 0;
9740     tng_data->input_file_len = 0;
9741     tng_data->output_file_path = 0;
9742     tng_data->output_file = 0;
9743
9744     tng_data->first_program_name = 0;
9745     tng_data->first_user_name = 0;
9746     tng_data->first_computer_name = 0;
9747     tng_data->first_pgp_signature = 0;
9748     tng_data->last_program_name = 0;
9749     tng_data->last_user_name = 0;
9750     tng_data->last_computer_name = 0;
9751     tng_data->last_pgp_signature = 0;
9752     tng_data->forcefield_name = 0;
9753
9754     seconds = time(0);
9755     if ( seconds == -1)
9756     {
9757         fprintf(stderr, "TNG library: Cannot get time. %s: %d\n", __FILE__, __LINE__);
9758     }
9759     else
9760     {
9761         tng_data->time = seconds;
9762     }
9763
9764     tng_data->var_num_atoms_flag = TNG_CONSTANT_N_ATOMS;
9765     tng_data->first_trajectory_frame_set_input_file_pos = -1;
9766     tng_data->last_trajectory_frame_set_input_file_pos = -1;
9767     tng_data->current_trajectory_frame_set_input_file_pos = -1;
9768     tng_data->first_trajectory_frame_set_output_file_pos = -1;
9769     tng_data->last_trajectory_frame_set_output_file_pos = -1;
9770     tng_data->current_trajectory_frame_set_output_file_pos = -1;
9771     tng_data->frame_set_n_frames = 100;
9772     tng_data->n_trajectory_frame_sets = 0;
9773     tng_data->medium_stride_length = 100;
9774     tng_data->long_stride_length = 10000;
9775
9776     tng_data->time_per_frame = -1;
9777
9778     tng_data->n_particle_data_blocks = 0;
9779     tng_data->n_data_blocks = 0;
9780
9781     tng_data->non_tr_particle_data = 0;
9782     tng_data->non_tr_data = 0;
9783
9784     tng_data->compress_algo_pos = 0;
9785     tng_data->compress_algo_vel = 0;
9786     tng_data->compression_precision = 1000;
9787     tng_data->distance_unit_exponential = -9;
9788
9789     frame_set->first_frame = -1;
9790     frame_set->n_mapping_blocks = 0;
9791     frame_set->mappings = 0;
9792     frame_set->molecule_cnt_list = 0;
9793
9794     frame_set->n_particle_data_blocks = 0;
9795     frame_set->n_data_blocks = 0;
9796
9797     frame_set->tr_particle_data = 0;
9798     frame_set->tr_data = 0;
9799
9800     frame_set->n_written_frames = 0;
9801     frame_set->n_unwritten_frames = 0;
9802
9803     frame_set->next_frame_set_file_pos = -1;
9804     frame_set->prev_frame_set_file_pos = -1;
9805     frame_set->medium_stride_next_frame_set_file_pos = -1;
9806     frame_set->medium_stride_prev_frame_set_file_pos = -1;
9807     frame_set->long_stride_next_frame_set_file_pos = -1;
9808     frame_set->long_stride_prev_frame_set_file_pos = -1;
9809
9810     frame_set->first_frame_time = -1;
9811
9812     tng_data->n_molecules = 0;
9813     tng_data->molecules = 0;
9814     tng_data->molecule_cnt_list = 0;
9815     tng_data->n_particles = 0;
9816
9817     {
9818       /* Check the endianness of the computer */
9819       static int32_t endianness_32 = 0x01234567;
9820       /* 0x01234567 */
9821       if ( *(const unsigned char*)&endianness_32 == 0x01 )
9822         {
9823           tng_data->endianness_32 = TNG_BIG_ENDIAN_32;
9824         }
9825
9826       /* 0x67452301 */
9827       else if( *(const unsigned char*)&endianness_32 == 0x67 )
9828         {
9829           tng_data->endianness_32 = TNG_LITTLE_ENDIAN_32;
9830
9831         }
9832
9833       /* 0x45670123 */
9834       else if ( *(const unsigned char*)&endianness_32 == 0x45 )
9835         {
9836           tng_data->endianness_32 = TNG_BYTE_PAIR_SWAP_32;
9837         }
9838     }
9839     {
9840       static int64_t endianness_64 = 0x0123456789ABCDEFLL;
9841       /* 0x0123456789ABCDEF */
9842       if ( *(const unsigned char*)&endianness_64 == 0x01 )
9843         {
9844           tng_data->endianness_64 = TNG_BIG_ENDIAN_64;
9845         }
9846
9847       /* 0xEFCDAB8967452301 */
9848       else if ( *(const unsigned char*)&endianness_64 == 0xEF )
9849         {
9850           tng_data->endianness_64 = TNG_LITTLE_ENDIAN_64;
9851         }
9852
9853       /* 0x89ABCDEF01234567 */
9854       else if ( *(const unsigned char*)&endianness_64 == 0x89 )
9855         {
9856           tng_data->endianness_64 = TNG_QUAD_SWAP_64;
9857         }
9858
9859       /* 0x45670123CDEF89AB */
9860       else if ( *(const unsigned char*)&endianness_64 == 0x45 )
9861         {
9862           tng_data->endianness_64 = TNG_BYTE_PAIR_SWAP_64;
9863         }
9864
9865       /* 0x23016745AB89EFCD */
9866       else if ( *(const unsigned char*)&endianness_64 == 0x23 )
9867         {
9868           tng_data->endianness_64 = TNG_BYTE_SWAP_64;
9869         }
9870     }
9871
9872     /* By default do not swap the byte order, i.e. keep the byte order of the
9873      * architecture. The input file endianness will be set when reading the
9874      * header. The output endianness can be changed - before the file is
9875      * written. */
9876     tng_data->input_endianness_swap_func_32 = 0;
9877     tng_data->input_endianness_swap_func_64 = 0;
9878     tng_data->output_endianness_swap_func_32 = 0;
9879     tng_data->output_endianness_swap_func_64 = 0;
9880
9881     tng_data->current_trajectory_frame_set.next_frame_set_file_pos = -1;
9882     tng_data->current_trajectory_frame_set.prev_frame_set_file_pos = -1;
9883     tng_data->current_trajectory_frame_set.n_frames = 0;
9884
9885     return(TNG_SUCCESS);
9886 }
9887
9888 tng_function_status DECLSPECDLLEXPORT tng_trajectory_destroy(tng_trajectory_t *tng_data_p)
9889 {
9890     int64_t i, j, k, l;
9891     int64_t n_particles, n_values_per_frame;
9892     tng_trajectory_t tng_data = *tng_data_p;
9893     tng_trajectory_frame_set_t frame_set;
9894
9895     if(!*tng_data_p)
9896     {
9897         return(TNG_SUCCESS);
9898     }
9899
9900     frame_set = &tng_data->current_trajectory_frame_set;
9901
9902     if(tng_data->input_file_path)
9903     {
9904         free(tng_data->input_file_path);
9905         tng_data->input_file_path = 0;
9906     }
9907
9908     if(tng_data->input_file)
9909     {
9910         if(tng_data->output_file == tng_data->input_file)
9911         {
9912             tng_frame_set_finalize(tng_data, TNG_USE_HASH);
9913             tng_data->output_file = 0;
9914         }
9915         fclose(tng_data->input_file);
9916         tng_data->input_file = 0;
9917     }
9918
9919     if(tng_data->output_file_path)
9920     {
9921         free(tng_data->output_file_path);
9922         tng_data->output_file_path = 0;
9923     }
9924
9925     if(tng_data->output_file)
9926     {
9927         /* FIXME: Do not always write the hash */
9928         tng_frame_set_finalize(tng_data, TNG_USE_HASH);
9929         fclose(tng_data->output_file);
9930         tng_data->output_file = 0;
9931     }
9932
9933     if(tng_data->first_program_name)
9934     {
9935         free(tng_data->first_program_name);
9936         tng_data->first_program_name = 0;
9937     }
9938
9939     if(tng_data->last_program_name)
9940     {
9941         free(tng_data->last_program_name);
9942         tng_data->last_program_name = 0;
9943     }
9944
9945     if(tng_data->first_user_name)
9946     {
9947         free(tng_data->first_user_name);
9948         tng_data->first_user_name = 0;
9949     }
9950
9951     if(tng_data->last_user_name)
9952     {
9953         free(tng_data->last_user_name);
9954         tng_data->last_user_name = 0;
9955     }
9956
9957     if(tng_data->first_computer_name)
9958     {
9959         free(tng_data->first_computer_name);
9960         tng_data->first_computer_name = 0;
9961     }
9962
9963     if(tng_data->last_computer_name)
9964     {
9965         free(tng_data->last_computer_name);
9966         tng_data->last_computer_name = 0;
9967     }
9968
9969     if(tng_data->first_pgp_signature)
9970     {
9971         free(tng_data->first_pgp_signature);
9972         tng_data->first_pgp_signature = 0;
9973     }
9974
9975     if(tng_data->last_pgp_signature)
9976     {
9977         free(tng_data->last_pgp_signature);
9978         tng_data->last_pgp_signature = 0;
9979     }
9980
9981     if(tng_data->forcefield_name)
9982     {
9983         free(tng_data->forcefield_name);
9984         tng_data->forcefield_name = 0;
9985     }
9986
9987     tng_frame_set_particle_mapping_free(tng_data);
9988
9989     if(frame_set->molecule_cnt_list)
9990     {
9991         free(frame_set->molecule_cnt_list);
9992         frame_set->molecule_cnt_list = 0;
9993     }
9994
9995     if(tng_data->var_num_atoms_flag)
9996     {
9997         n_particles = frame_set->n_particles;
9998     }
9999     else
10000     {
10001         n_particles = tng_data->n_particles;
10002     }
10003
10004     if(tng_data->non_tr_particle_data)
10005     {
10006         for(i = 0; i < tng_data->n_particle_data_blocks; i++)
10007         {
10008             if(tng_data->non_tr_particle_data[i].values)
10009             {
10010                 free(tng_data->non_tr_particle_data[i].values);
10011                 tng_data->non_tr_particle_data[i].values = 0;
10012             }
10013
10014             if(tng_data->non_tr_particle_data[i].strings)
10015             {
10016                 n_values_per_frame = tng_data->non_tr_particle_data[i].
10017                                      n_values_per_frame;
10018                 if(tng_data->non_tr_particle_data[i].strings[0])
10019                 {
10020                     for(j = 0; j < n_particles; j++)
10021                     {
10022                         if(tng_data->non_tr_particle_data[i].strings[0][j])
10023                         {
10024                             for(k = 0; k < n_values_per_frame; k++)
10025                             {
10026                                 if(tng_data->non_tr_particle_data[i].
10027                                    strings[0][j][k])
10028                                 {
10029                                     free(tng_data->non_tr_particle_data[i].
10030                                          strings[0][j][k]);
10031                                     tng_data->non_tr_particle_data[i].
10032                                     strings[0][j][k] = 0;
10033                                 }
10034                             }
10035                             free(tng_data->non_tr_particle_data[i].
10036                                  strings[0][j]);
10037                             tng_data->non_tr_particle_data[i].strings[0][j] = 0;
10038                         }
10039                     }
10040                     free(tng_data->non_tr_particle_data[i].strings[0]);
10041                     tng_data->non_tr_particle_data[i].strings[0] = 0;
10042                 }
10043                 free(tng_data->non_tr_particle_data[i].strings);
10044                 tng_data->non_tr_particle_data[i].strings = 0;
10045             }
10046
10047             if(tng_data->non_tr_particle_data[i].block_name)
10048             {
10049                 free(tng_data->non_tr_particle_data[i].block_name);
10050                 tng_data->non_tr_particle_data[i].block_name = 0;
10051             }
10052         }
10053         free(tng_data->non_tr_particle_data);
10054         tng_data->non_tr_particle_data = 0;
10055     }
10056
10057     if(tng_data->non_tr_data)
10058     {
10059         for(i = 0; i < tng_data->n_data_blocks; i++)
10060         {
10061             if(tng_data->non_tr_data[i].values)
10062             {
10063                 free(tng_data->non_tr_data[i].values);
10064                 tng_data->non_tr_data[i].values = 0;
10065             }
10066
10067             if(tng_data->non_tr_data[i].strings)
10068             {
10069                 n_values_per_frame = tng_data->non_tr_data[i].
10070                                      n_values_per_frame;
10071                 if(tng_data->non_tr_data[i].strings[0])
10072                 {
10073                     for(j = 0; j < n_values_per_frame; j++)
10074                     {
10075                         if(tng_data->non_tr_data[i].strings[0][j])
10076                         {
10077                             free(tng_data->non_tr_data[i].strings[0][j]);
10078                             tng_data->non_tr_data[i].strings[0][j] = 0;
10079                         }
10080                     }
10081                     free(tng_data->non_tr_data[i].strings[0]);
10082                     tng_data->non_tr_data[i].strings[0] = 0;
10083                 }
10084                 free(tng_data->non_tr_data[i].strings);
10085                 tng_data->non_tr_data[i].strings = 0;
10086             }
10087
10088             if(tng_data->non_tr_data[i].block_name)
10089             {
10090                 free(tng_data->non_tr_data[i].block_name);
10091                 tng_data->non_tr_data[i].block_name = 0;
10092             }
10093         }
10094         free(tng_data->non_tr_data);
10095         tng_data->non_tr_data = 0;
10096     }
10097
10098     tng_data->n_particle_data_blocks = 0;
10099     tng_data->n_data_blocks = 0;
10100
10101     if(tng_data->compress_algo_pos)
10102     {
10103         free(tng_data->compress_algo_pos);
10104         tng_data->compress_algo_pos = 0;
10105     }
10106     if(tng_data->compress_algo_vel)
10107     {
10108         free(tng_data->compress_algo_vel);
10109         tng_data->compress_algo_vel = 0;
10110     }
10111
10112     if(frame_set->tr_particle_data)
10113     {
10114         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
10115         {
10116             if(frame_set->tr_particle_data[i].values)
10117             {
10118                 free(frame_set->tr_particle_data[i].values);
10119                 frame_set->tr_particle_data[i].values = 0;
10120             }
10121
10122             if(frame_set->tr_particle_data[i].strings)
10123             {
10124                 n_values_per_frame = frame_set->tr_particle_data[i].
10125                                      n_values_per_frame;
10126                 for(j = 0; j < frame_set->tr_particle_data[i].n_frames; j++)
10127                 {
10128                     if(frame_set->tr_particle_data[i].strings[j])
10129                     {
10130                         for(k = 0; k < n_particles; k++)
10131                         {
10132                             if(frame_set->tr_particle_data[i].
10133                                 strings[j][k])
10134                             {
10135                                 for(l = 0; l < n_values_per_frame; l++)
10136                                 {
10137                                     if(frame_set->tr_particle_data[i].
10138                                         strings[j][k][l])
10139                                     {
10140                                         free(frame_set->tr_particle_data[i].
10141                                                 strings[j][k][l]);
10142                                         frame_set->tr_particle_data[i].
10143                                         strings[j][k][l] = 0;
10144                                     }
10145                                 }
10146                                 free(frame_set->tr_particle_data[i].
10147                                         strings[j][k]);
10148                                 frame_set->tr_particle_data[i].
10149                                 strings[j][k] = 0;
10150                             }
10151                         }
10152                         free(frame_set->tr_particle_data[i].strings[j]);
10153                         frame_set->tr_particle_data[i].strings[j] = 0;
10154                     }
10155                 }
10156                 free(frame_set->tr_particle_data[i].strings);
10157                 frame_set->tr_particle_data[i].strings = 0;
10158             }
10159
10160             if(frame_set->tr_particle_data[i].block_name)
10161             {
10162                 free(frame_set->tr_particle_data[i].block_name);
10163                 frame_set->tr_particle_data[i].block_name = 0;
10164             }
10165         }
10166         free(frame_set->tr_particle_data);
10167         frame_set->tr_particle_data = 0;
10168     }
10169
10170     if(frame_set->tr_data)
10171     {
10172         for(i = 0; i < frame_set->n_data_blocks; i++)
10173         {
10174             if(frame_set->tr_data[i].values)
10175             {
10176                 free(frame_set->tr_data[i].values);
10177                 frame_set->tr_data[i].values = 0;
10178             }
10179
10180             if(frame_set->tr_data[i].strings)
10181             {
10182                 n_values_per_frame = frame_set->tr_data[i].
10183                                      n_values_per_frame;
10184                 for(j = 0; j < frame_set->tr_data[i].n_frames; j++)
10185                 {
10186                     if(frame_set->tr_data[i].strings[j])
10187                     {
10188                         for(k = 0; k < n_values_per_frame; k++)
10189                         {
10190                             if(frame_set->tr_data[i].strings[j][k])
10191                             {
10192                                 free(frame_set->tr_data[i].strings[j][k]);
10193                                 frame_set->tr_data[i].strings[j][k] = 0;
10194                             }
10195                         }
10196                         free(frame_set->tr_data[i].strings[j]);
10197                         frame_set->tr_data[i].strings[j] = 0;
10198                     }
10199                 }
10200                 free(frame_set->tr_data[i].strings);
10201                 frame_set->tr_data[i].strings = 0;
10202             }
10203
10204             if(frame_set->tr_data[i].block_name)
10205             {
10206                 free(frame_set->tr_data[i].block_name);
10207                 frame_set->tr_data[i].block_name = 0;
10208             }
10209         }
10210         free(frame_set->tr_data);
10211         frame_set->tr_data = 0;
10212     }
10213
10214     frame_set->n_particle_data_blocks = 0;
10215     frame_set->n_data_blocks = 0;
10216
10217     if(tng_data->molecules)
10218     {
10219         for(i = 0; i < tng_data->n_molecules; i++)
10220         {
10221             tng_molecule_destroy(tng_data, &tng_data->molecules[i]);
10222         }
10223         free(tng_data->molecules);
10224         tng_data->molecules = 0;
10225         tng_data->n_molecules = 0;
10226     }
10227     if(tng_data->molecule_cnt_list)
10228     {
10229         free(tng_data->molecule_cnt_list);
10230         tng_data->molecule_cnt_list = 0;
10231     }
10232
10233     free(*tng_data_p);
10234     *tng_data_p = 0;
10235
10236     return(TNG_SUCCESS);
10237 }
10238
10239 tng_function_status DECLSPECDLLEXPORT tng_trajectory_init_from_src(tng_trajectory_t src,
10240                                                  tng_trajectory_t *dest_p)
10241 {
10242     tng_trajectory_frame_set_t frame_set;
10243     tng_trajectory_t dest;
10244
10245     TNG_ASSERT(src != 0, "TNG library: Source trajectory must not be NULL.");
10246
10247     *dest_p = malloc(sizeof(struct tng_trajectory));
10248     if(!*dest_p)
10249     {
10250         fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
10251                sizeof(struct tng_trajectory), __FILE__, __LINE__);
10252         return(TNG_CRITICAL);
10253     }
10254
10255     dest = *dest_p;
10256
10257     frame_set = &dest->current_trajectory_frame_set;
10258
10259     dest->input_file_path = malloc(strlen(src->input_file_path) + 1);
10260     if(!dest->input_file_path)
10261     {
10262         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
10263                (int)strlen(src->input_file_path) + 1, __FILE__, __LINE__);
10264         return(TNG_CRITICAL);
10265     }
10266     strcpy(dest->input_file_path, src->input_file_path);
10267     dest->input_file = 0;
10268     dest->input_file_len = src->input_file_len;
10269     dest->output_file_path = malloc(strlen(src->output_file_path) + 1);
10270     if(!dest->output_file_path)
10271     {
10272         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
10273                (int)strlen(src->output_file_path) + 1, __FILE__, __LINE__);
10274         return(TNG_CRITICAL);
10275     }
10276     strcpy(dest->output_file_path, src->output_file_path);
10277     dest->output_file = 0;
10278
10279     dest->first_program_name = 0;
10280     dest->first_user_name = 0;
10281     dest->first_computer_name = 0;
10282     dest->first_pgp_signature = 0;
10283     dest->last_program_name = 0;
10284     dest->last_user_name = 0;
10285     dest->last_computer_name = 0;
10286     dest->last_pgp_signature = 0;
10287     dest->forcefield_name = 0;
10288
10289     dest->var_num_atoms_flag = src->var_num_atoms_flag;
10290     dest->first_trajectory_frame_set_input_file_pos =
10291     src->first_trajectory_frame_set_input_file_pos;
10292     dest->last_trajectory_frame_set_input_file_pos =
10293     src->last_trajectory_frame_set_input_file_pos;
10294     dest->current_trajectory_frame_set_input_file_pos =
10295     src->current_trajectory_frame_set_input_file_pos;
10296     dest->first_trajectory_frame_set_output_file_pos =
10297     src->first_trajectory_frame_set_output_file_pos;
10298     dest->last_trajectory_frame_set_output_file_pos =
10299     src->last_trajectory_frame_set_output_file_pos;
10300     dest->current_trajectory_frame_set_output_file_pos =
10301     src->current_trajectory_frame_set_output_file_pos;
10302     dest->frame_set_n_frames = src->frame_set_n_frames;
10303     dest->n_trajectory_frame_sets = src->n_trajectory_frame_sets;
10304     dest->medium_stride_length = src->medium_stride_length;
10305     dest->long_stride_length = src->long_stride_length;
10306
10307     dest->time_per_frame = src->time_per_frame;
10308
10309     /* Currently the non trajectory data blocks are not copied since it
10310      * can lead to problems when freeing memory in a parallel block. */
10311     dest->n_particle_data_blocks = 0;
10312     dest->n_data_blocks = 0;
10313     dest->non_tr_particle_data = 0;
10314     dest->non_tr_data = 0;
10315
10316     dest->compress_algo_pos = 0;
10317     dest->compress_algo_vel = 0;
10318     dest->distance_unit_exponential = -9;
10319     dest->compression_precision = 1000;
10320
10321     frame_set->n_mapping_blocks = 0;
10322     frame_set->mappings = 0;
10323     frame_set->molecule_cnt_list = 0;
10324
10325     frame_set->n_particle_data_blocks = 0;
10326     frame_set->n_data_blocks = 0;
10327
10328     frame_set->tr_particle_data = 0;
10329     frame_set->tr_data = 0;
10330
10331     frame_set->next_frame_set_file_pos = -1;
10332     frame_set->prev_frame_set_file_pos = -1;
10333     frame_set->medium_stride_next_frame_set_file_pos = -1;
10334     frame_set->medium_stride_prev_frame_set_file_pos = -1;
10335     frame_set->long_stride_next_frame_set_file_pos = -1;
10336     frame_set->long_stride_prev_frame_set_file_pos = -1;
10337     frame_set->first_frame = -1;
10338
10339     dest->n_molecules = 0;
10340     dest->molecules = 0;
10341     dest->molecule_cnt_list = 0;
10342     dest->n_particles = src->n_particles;
10343
10344     dest->endianness_32 = src->endianness_32;
10345     dest->endianness_64 = src->endianness_64;
10346     dest->input_endianness_swap_func_32 = src->input_endianness_swap_func_32;
10347     dest->input_endianness_swap_func_64 = src->input_endianness_swap_func_64;
10348     dest->output_endianness_swap_func_32 = src->output_endianness_swap_func_32;
10349     dest->output_endianness_swap_func_64 = src->output_endianness_swap_func_64;
10350
10351     dest->current_trajectory_frame_set.next_frame_set_file_pos = -1;
10352     dest->current_trajectory_frame_set.prev_frame_set_file_pos = -1;
10353     dest->current_trajectory_frame_set.n_frames = 0;
10354
10355     return(TNG_SUCCESS);
10356 }
10357
10358 tng_function_status DECLSPECDLLEXPORT tng_input_file_get(const tng_trajectory_t tng_data,
10359                                        char *file_name, const int max_len)
10360 {
10361     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10362     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
10363
10364     strncpy(file_name, tng_data->input_file_path, max_len - 1);
10365     file_name[max_len - 1] = 0;
10366
10367     if(strlen(tng_data->input_file_path) > (unsigned int)max_len - 1)
10368     {
10369         return(TNG_FAILURE);
10370     }
10371     return(TNG_SUCCESS);
10372 }
10373
10374 tng_function_status DECLSPECDLLEXPORT tng_input_file_set(tng_trajectory_t tng_data,
10375                                                          const char *file_name)
10376 {
10377     unsigned int len;
10378     char *temp;
10379
10380     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10381     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
10382
10383
10384     if(tng_data->input_file_path && strcmp(tng_data->input_file_path,
10385                                            file_name) == 0)
10386     {
10387         return(TNG_SUCCESS);
10388     }
10389
10390     if(tng_data->input_file)
10391     {
10392         fclose(tng_data->input_file);
10393     }
10394
10395     len = tng_min_i((int)strlen(file_name) + 1, TNG_MAX_STR_LEN);
10396     temp = realloc(tng_data->input_file_path, len);
10397     if(!temp)
10398     {
10399         fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10400                __FILE__, __LINE__);
10401         free(tng_data->input_file_path);
10402         tng_data->input_file_path = 0;
10403         return(TNG_CRITICAL);
10404     }
10405     tng_data->input_file_path = temp;
10406
10407     strncpy(tng_data->input_file_path, file_name, len);
10408
10409     return(tng_input_file_init(tng_data));
10410 }
10411
10412 tng_function_status tng_output_file_get(const tng_trajectory_t tng_data,
10413                                        char *file_name, const int max_len)
10414 {
10415     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10416     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
10417
10418     strncpy(file_name, tng_data->output_file_path, max_len - 1);
10419     file_name[max_len - 1] = 0;
10420
10421     if(strlen(tng_data->output_file_path) > (unsigned int)max_len - 1)
10422     {
10423         return(TNG_FAILURE);
10424     }
10425     return(TNG_SUCCESS);
10426 }
10427
10428 tng_function_status DECLSPECDLLEXPORT tng_output_file_set(tng_trajectory_t tng_data,
10429                                                           const char *file_name)
10430 {
10431     int len;
10432     char *temp;
10433
10434     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10435     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
10436
10437     if(tng_data->output_file_path &&
10438        strcmp(tng_data->output_file_path, file_name) == 0)
10439     {
10440         return(TNG_SUCCESS);
10441     }
10442
10443     if(tng_data->output_file)
10444     {
10445         fclose(tng_data->output_file);
10446     }
10447
10448     len = tng_min_i((int)strlen(file_name) + 1, TNG_MAX_STR_LEN);
10449     temp = realloc(tng_data->output_file_path, len);
10450     if(!temp)
10451     {
10452         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
10453                __FILE__, __LINE__);
10454         free(tng_data->output_file_path);
10455         tng_data->output_file_path = 0;
10456         return(TNG_CRITICAL);
10457     }
10458     tng_data->output_file_path = temp;
10459
10460     strncpy(tng_data->output_file_path, file_name, len);
10461
10462     return(tng_output_file_init(tng_data));
10463 }
10464
10465 tng_function_status DECLSPECDLLEXPORT tng_output_append_file_set
10466                 (tng_trajectory_t tng_data,
10467                  const char *file_name)
10468 {
10469     int len;
10470     char *temp;
10471
10472     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10473     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
10474
10475     if(tng_data->output_file_path &&
10476        strcmp(tng_data->output_file_path, file_name) == 0)
10477     {
10478         return(TNG_SUCCESS);
10479     }
10480
10481     if(tng_data->output_file)
10482     {
10483         fclose(tng_data->output_file);
10484     }
10485
10486     len = tng_min_i((int)strlen(file_name) + 1, TNG_MAX_STR_LEN);
10487     temp = realloc(tng_data->output_file_path, len);
10488     if(!temp)
10489     {
10490         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
10491                __FILE__, __LINE__);
10492         free(tng_data->output_file_path);
10493         tng_data->output_file_path = 0;
10494         return(TNG_CRITICAL);
10495     }
10496     tng_data->output_file_path = temp;
10497
10498     strncpy(tng_data->output_file_path, file_name, len);
10499
10500     tng_data->output_file = fopen(tng_data->output_file_path, "rb+");
10501     if(!tng_data->output_file)
10502     {
10503         fprintf(stderr, "TNG library: Cannot open file %s. %s: %d\n",
10504                 tng_data->output_file_path, __FILE__, __LINE__);
10505         return(TNG_CRITICAL);
10506     }
10507     tng_data->input_file = tng_data->output_file;
10508
10509     return(TNG_SUCCESS);
10510 }
10511
10512 tng_function_status DECLSPECDLLEXPORT tng_output_file_endianness_get
10513                 (const tng_trajectory_t tng_data, tng_file_endianness *endianness)
10514 {
10515     tng_endianness_32 end_32;
10516     tng_endianness_64 end_64;
10517
10518     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10519     TNG_ASSERT(endianness, "TNG library: endianness must not be a NULL pointer");
10520
10521     if(tng_data->output_endianness_swap_func_32)
10522     {
10523         /* If other endianness variants are added they must be added here as well */
10524         if(tng_data->output_endianness_swap_func_32 ==
10525            &tng_swap_byte_order_big_endian_32)
10526         {
10527             end_32 = TNG_BIG_ENDIAN_32;
10528         }
10529         else if(tng_data->output_endianness_swap_func_32 ==
10530                 &tng_swap_byte_order_little_endian_32)
10531         {
10532             end_32 = TNG_LITTLE_ENDIAN_32;
10533         }
10534         else
10535         {
10536             return(TNG_FAILURE);
10537         }
10538     }
10539     else
10540     {
10541         end_32 = (tng_endianness_32)tng_data->endianness_32;
10542     }
10543
10544     if(tng_data->output_endianness_swap_func_64)
10545     {
10546         /* If other endianness variants are added they must be added here as well */
10547         if(tng_data->output_endianness_swap_func_64 ==
10548            &tng_swap_byte_order_big_endian_64)
10549         {
10550             end_64 = TNG_BIG_ENDIAN_64;
10551         }
10552         else if(tng_data->output_endianness_swap_func_64 ==
10553                 &tng_swap_byte_order_little_endian_64)
10554         {
10555             end_64 = TNG_LITTLE_ENDIAN_64;
10556         }
10557         else
10558         {
10559             return(TNG_FAILURE);
10560         }
10561     }
10562     else
10563     {
10564         end_64 = (tng_endianness_64)tng_data->endianness_64;
10565     }
10566
10567     if((int)end_32 != (int)end_64)
10568     {
10569         return(TNG_FAILURE);
10570     }
10571
10572     if(end_32 == TNG_LITTLE_ENDIAN_32)
10573     {
10574         *endianness = TNG_LITTLE_ENDIAN;
10575     }
10576
10577     else if(end_32 == TNG_BIG_ENDIAN_32)
10578     {
10579         *endianness = TNG_BIG_ENDIAN;
10580     }
10581     else
10582     {
10583         return(TNG_FAILURE);
10584     }
10585
10586     return(TNG_SUCCESS);
10587 }
10588
10589 tng_function_status DECLSPECDLLEXPORT tng_output_file_endianness_set
10590                 (tng_trajectory_t tng_data,
10591                  const tng_file_endianness endianness)
10592 {
10593     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10594
10595     /* Tne endianness cannot be changed if the data has already been written
10596      * to the output file. */
10597     if(ftell(tng_data->output_file) > 0)
10598     {
10599         return(TNG_FAILURE);
10600     }
10601
10602     if(endianness == TNG_BIG_ENDIAN)
10603     {
10604         if(tng_data->endianness_32 == TNG_BIG_ENDIAN_32)
10605         {
10606             tng_data->output_endianness_swap_func_32 = 0;
10607         }
10608         else
10609         {
10610             tng_data->output_endianness_swap_func_32 =
10611             &tng_swap_byte_order_big_endian_32;
10612         }
10613         if(tng_data->endianness_64 == TNG_BIG_ENDIAN_64)
10614         {
10615             tng_data->output_endianness_swap_func_64 = 0;
10616         }
10617         else
10618         {
10619             tng_data->output_endianness_swap_func_64 =
10620             &tng_swap_byte_order_big_endian_64;
10621         }
10622         return(TNG_SUCCESS);
10623     }
10624     else if(endianness == TNG_LITTLE_ENDIAN)
10625     {
10626         if(tng_data->endianness_32 == TNG_LITTLE_ENDIAN_32)
10627         {
10628             tng_data->output_endianness_swap_func_32 = 0;
10629         }
10630         else
10631         {
10632             tng_data->output_endianness_swap_func_32 =
10633             &tng_swap_byte_order_little_endian_32;
10634         }
10635         if(tng_data->endianness_64 == TNG_LITTLE_ENDIAN_64)
10636         {
10637             tng_data->output_endianness_swap_func_64 = 0;
10638         }
10639         else
10640         {
10641             tng_data->output_endianness_swap_func_64 =
10642             &tng_swap_byte_order_little_endian_64;
10643         }
10644         return(TNG_SUCCESS);
10645     }
10646
10647     /* If the specified endianness is neither big nor little endian return a
10648      * failure. */
10649     return(TNG_FAILURE);
10650 }
10651
10652 tng_function_status DECLSPECDLLEXPORT tng_first_program_name_get
10653                     (const tng_trajectory_t tng_data,
10654                      char *name, const int max_len)
10655 {
10656     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10657     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10658
10659     strncpy(name, tng_data->first_program_name, max_len - 1);
10660     name[max_len - 1] = 0;
10661
10662     if(strlen(tng_data->first_program_name) > (unsigned int)max_len - 1)
10663     {
10664         return(TNG_FAILURE);
10665     }
10666     return(TNG_SUCCESS);
10667 }
10668
10669 tng_function_status DECLSPECDLLEXPORT tng_first_program_name_set(tng_trajectory_t tng_data,
10670                                                                  const char *new_name)
10671 {
10672     unsigned int len;
10673
10674     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10675     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10676
10677     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10678
10679     if(tng_data->first_program_name && strlen(tng_data->first_program_name) < len)
10680     {
10681         free(tng_data->first_program_name);
10682         tng_data->first_program_name = 0;
10683     }
10684     if(!tng_data->first_program_name)
10685     {
10686         tng_data->first_program_name = malloc(len);
10687         if(!tng_data->first_program_name)
10688         {
10689             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10690                    __FILE__, __LINE__);
10691             return(TNG_CRITICAL);
10692         }
10693     }
10694
10695     strncpy(tng_data->first_program_name, new_name, len);
10696
10697     return(TNG_SUCCESS);
10698 }
10699
10700 tng_function_status DECLSPECDLLEXPORT tng_last_program_name_get
10701                     (const tng_trajectory_t tng_data,
10702                      char *name, const int max_len)
10703 {
10704     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10705     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10706
10707     strncpy(name, tng_data->last_program_name, max_len - 1);
10708     name[max_len - 1] = 0;
10709
10710     if(strlen(tng_data->last_program_name) > (unsigned int)max_len - 1)
10711     {
10712         return(TNG_FAILURE);
10713     }
10714     return(TNG_SUCCESS);
10715 }
10716
10717 tng_function_status DECLSPECDLLEXPORT tng_last_program_name_set
10718                     (tng_trajectory_t tng_data,
10719                      const char *new_name)
10720 {
10721     unsigned int len;
10722
10723     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10724     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10725
10726     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10727
10728     if(tng_data->last_program_name && strlen(tng_data->last_program_name) < len)
10729     {
10730         free(tng_data->last_program_name);
10731         tng_data->last_program_name = 0;
10732     }
10733     if(!tng_data->last_program_name)
10734     {
10735         tng_data->last_program_name = malloc(len);
10736         if(!tng_data->last_program_name)
10737         {
10738             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10739                    __FILE__, __LINE__);
10740             return(TNG_CRITICAL);
10741         }
10742     }
10743
10744     strncpy(tng_data->last_program_name, new_name, len);
10745
10746     return(TNG_SUCCESS);
10747 }
10748
10749 tng_function_status DECLSPECDLLEXPORT tng_first_user_name_get
10750                     (const tng_trajectory_t tng_data,
10751                      char *name, const int max_len)
10752 {
10753     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10754     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10755
10756     strncpy(name, tng_data->first_user_name, max_len - 1);
10757     name[max_len - 1] = 0;
10758
10759     if(strlen(tng_data->first_user_name) > (unsigned int)max_len - 1)
10760     {
10761         return(TNG_FAILURE);
10762     }
10763     return(TNG_SUCCESS);
10764 }
10765
10766 tng_function_status DECLSPECDLLEXPORT tng_first_user_name_set
10767                     (tng_trajectory_t tng_data,
10768                      const char *new_name)
10769 {
10770     unsigned int len;
10771
10772     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10773     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10774
10775     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10776
10777     /* If the currently stored string length is not enough to store the new
10778      * string it is freed and reallocated. */
10779     if(tng_data->first_user_name && strlen(tng_data->first_user_name) < len)
10780     {
10781         free(tng_data->first_user_name);
10782         tng_data->first_user_name = 0;
10783     }
10784     if(!tng_data->first_user_name)
10785     {
10786         tng_data->first_user_name = malloc(len);
10787         if(!tng_data->first_user_name)
10788         {
10789             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10790                    __FILE__, __LINE__);
10791             return(TNG_CRITICAL);
10792         }
10793     }
10794
10795     strncpy(tng_data->first_user_name, new_name, len);
10796
10797     return(TNG_SUCCESS);
10798 }
10799
10800 tng_function_status DECLSPECDLLEXPORT tng_last_user_name_get
10801                     (const tng_trajectory_t tng_data,
10802                      char *name, const int max_len)
10803 {
10804     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10805     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10806
10807     strncpy(name, tng_data->last_user_name, max_len - 1);
10808     name[max_len - 1] = 0;
10809
10810     if(strlen(tng_data->last_user_name) > (unsigned int)max_len - 1)
10811     {
10812         return(TNG_FAILURE);
10813     }
10814     return(TNG_SUCCESS);
10815 }
10816
10817 tng_function_status DECLSPECDLLEXPORT tng_last_user_name_set
10818                     (tng_trajectory_t tng_data,
10819                      const char *new_name)
10820 {
10821     unsigned int len;
10822
10823     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10824     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10825
10826     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10827
10828     /* If the currently stored string length is not enough to store the new
10829      * string it is freed and reallocated. */
10830     if(tng_data->last_user_name && strlen(tng_data->last_user_name) < len)
10831     {
10832         free(tng_data->last_user_name);
10833         tng_data->last_user_name = 0;
10834     }
10835     if(!tng_data->last_user_name)
10836     {
10837         tng_data->last_user_name = malloc(len);
10838         if(!tng_data->last_user_name)
10839         {
10840             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10841                    __FILE__, __LINE__);
10842             return(TNG_CRITICAL);
10843         }
10844     }
10845
10846     strncpy(tng_data->last_user_name, new_name, len);
10847
10848     return(TNG_SUCCESS);
10849 }
10850
10851 tng_function_status DECLSPECDLLEXPORT tng_first_computer_name_get
10852                     (const tng_trajectory_t tng_data,
10853                      char *name, const int max_len)
10854 {
10855     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10856     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10857
10858     strncpy(name, tng_data->first_computer_name, max_len - 1);
10859     name[max_len - 1] = 0;
10860
10861     if(strlen(tng_data->first_computer_name) > (unsigned int)max_len - 1)
10862     {
10863         return(TNG_FAILURE);
10864     }
10865     return(TNG_SUCCESS);
10866 }
10867
10868 tng_function_status DECLSPECDLLEXPORT tng_first_computer_name_set
10869                     (tng_trajectory_t tng_data,
10870                      const char *new_name)
10871 {
10872     unsigned int len;
10873
10874     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10875     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10876
10877     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10878
10879     /* If the currently stored string length is not enough to store the new
10880      * string it is freed and reallocated. */
10881     if(tng_data->first_computer_name && strlen(tng_data->first_computer_name) < len)
10882     {
10883         free(tng_data->first_computer_name);
10884         tng_data->first_computer_name = 0;
10885     }
10886     if(!tng_data->first_computer_name)
10887     {
10888         tng_data->first_computer_name = malloc(len);
10889         if(!tng_data->first_computer_name)
10890         {
10891             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10892                    __FILE__, __LINE__);
10893             return(TNG_CRITICAL);
10894         }
10895     }
10896
10897     strncpy(tng_data->first_computer_name, new_name, len);
10898
10899     return(TNG_SUCCESS);
10900 }
10901
10902 tng_function_status DECLSPECDLLEXPORT tng_last_computer_name_get
10903                     (const tng_trajectory_t tng_data,
10904                      char *name, const int max_len)
10905 {
10906     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10907     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10908
10909     strncpy(name, tng_data->last_computer_name, max_len - 1);
10910     name[max_len - 1] = 0;
10911
10912     if(strlen(tng_data->last_computer_name) > (unsigned int)max_len - 1)
10913     {
10914         return(TNG_FAILURE);
10915     }
10916     return(TNG_SUCCESS);
10917 }
10918
10919 tng_function_status DECLSPECDLLEXPORT tng_last_computer_name_set
10920                     (tng_trajectory_t tng_data,
10921                      const char *new_name)
10922 {
10923     unsigned int len;
10924
10925     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10926     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10927
10928     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10929
10930     /* If the currently stored string length is not enough to store the new
10931      * string it is freed and reallocated. */
10932     if(tng_data->last_computer_name && strlen(tng_data->last_computer_name) <
10933         len)
10934     {
10935         free(tng_data->last_computer_name);
10936         tng_data->last_computer_name = 0;
10937     }
10938     if(!tng_data->last_computer_name)
10939     {
10940         tng_data->last_computer_name = malloc(len);
10941         if(!tng_data->last_computer_name)
10942         {
10943             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10944                    __FILE__, __LINE__);
10945             return(TNG_CRITICAL);
10946         }
10947     }
10948
10949     strncpy(tng_data->last_computer_name, new_name, len);
10950
10951     return(TNG_SUCCESS);
10952 }
10953
10954 tng_function_status DECLSPECDLLEXPORT tng_first_signature_get
10955                     (const tng_trajectory_t tng_data,
10956                      char *signature, const int max_len)
10957 {
10958     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10959     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
10960
10961     strncpy(signature, tng_data->first_pgp_signature, max_len - 1);
10962     signature[max_len - 1] = 0;
10963
10964     if(strlen(tng_data->first_pgp_signature) > (unsigned int)max_len - 1)
10965     {
10966         return(TNG_FAILURE);
10967     }
10968     return(TNG_SUCCESS);
10969 }
10970
10971 tng_function_status DECLSPECDLLEXPORT tng_first_signature_set
10972                     (tng_trajectory_t tng_data,
10973                      const char *signature)
10974 {
10975     unsigned int len;
10976
10977     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10978     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
10979
10980     len = tng_min_i((int)strlen(signature) + 1, TNG_MAX_STR_LEN);
10981
10982     /* If the currently stored string length is not enough to store the new
10983      * string it is freed and reallocated. */
10984     if(tng_data->first_pgp_signature && strlen(tng_data->first_pgp_signature) <
10985         len)
10986     {
10987         free(tng_data->first_pgp_signature);
10988         tng_data->first_pgp_signature = 0;
10989     }
10990     if(!tng_data->first_pgp_signature)
10991     {
10992         tng_data->first_pgp_signature = malloc(len);
10993         if(!tng_data->first_pgp_signature)
10994         {
10995             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10996                    __FILE__, __LINE__);
10997             return(TNG_CRITICAL);
10998         }
10999     }
11000
11001     strncpy(tng_data->first_pgp_signature, signature, len);
11002
11003     return(TNG_SUCCESS);
11004 }
11005
11006 tng_function_status DECLSPECDLLEXPORT tng_last_signature_get
11007                     (const tng_trajectory_t tng_data,
11008                      char *signature, const int max_len)
11009 {
11010     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11011     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
11012
11013     strncpy(signature, tng_data->last_pgp_signature, max_len - 1);
11014     signature[max_len - 1] = 0;
11015
11016     if(strlen(tng_data->last_pgp_signature) > (unsigned int)max_len - 1)
11017     {
11018         return(TNG_FAILURE);
11019     }
11020     return(TNG_SUCCESS);
11021 }
11022
11023 tng_function_status DECLSPECDLLEXPORT tng_last_signature_set
11024                     (tng_trajectory_t tng_data,
11025                      const char *signature)
11026 {
11027     unsigned int len;
11028
11029     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11030     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
11031
11032     len = tng_min_i((int)strlen(signature) + 1, TNG_MAX_STR_LEN);
11033
11034     /* If the currently stored string length is not enough to store the new
11035      * string it is freed and reallocated. */
11036     if(tng_data->last_pgp_signature && strlen(tng_data->last_pgp_signature) <
11037         len)
11038     {
11039         free(tng_data->last_pgp_signature);
11040         tng_data->last_pgp_signature = 0;
11041     }
11042     if(!tng_data->last_pgp_signature)
11043     {
11044         tng_data->last_pgp_signature = malloc(len);
11045         if(!tng_data->last_pgp_signature)
11046         {
11047             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
11048                    __FILE__, __LINE__);
11049             return(TNG_CRITICAL);
11050         }
11051     }
11052
11053     strncpy(tng_data->last_pgp_signature, signature, len);
11054
11055     return(TNG_SUCCESS);
11056 }
11057
11058 tng_function_status DECLSPECDLLEXPORT tng_forcefield_name_get
11059                     (const tng_trajectory_t tng_data,
11060                      char *name, const int max_len)
11061 {
11062     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11063     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
11064
11065     strncpy(name, tng_data->forcefield_name, max_len - 1);
11066     name[max_len - 1] = 0;
11067
11068     if(strlen(tng_data->forcefield_name) > (unsigned int)max_len - 1)
11069     {
11070         return(TNG_FAILURE);
11071     }
11072     return(TNG_SUCCESS);
11073 }
11074
11075 tng_function_status DECLSPECDLLEXPORT tng_forcefield_name_set
11076                     (tng_trajectory_t tng_data,
11077                      const char *new_name)
11078 {
11079     unsigned int len;
11080
11081     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11082     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
11083
11084     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
11085
11086     /* If the currently stored string length is not enough to store the new
11087      * string it is freed and reallocated. */
11088     if(tng_data->forcefield_name && strlen(tng_data->forcefield_name) < len)
11089     {
11090         free(tng_data->forcefield_name);
11091         tng_data->forcefield_name = 0;
11092     }
11093     if(!tng_data->forcefield_name)
11094     {
11095         tng_data->forcefield_name = malloc(len);
11096         if(!tng_data->forcefield_name)
11097         {
11098             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
11099                    __FILE__, __LINE__);
11100             return(TNG_CRITICAL);
11101         }
11102     }
11103
11104     strncpy(tng_data->forcefield_name, new_name, len);
11105
11106     return(TNG_SUCCESS);
11107 }
11108
11109 tng_function_status DECLSPECDLLEXPORT tng_medium_stride_length_get
11110                     (const tng_trajectory_t tng_data,
11111                      int64_t *len)
11112 {
11113     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11114     TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
11115
11116     *len = tng_data->medium_stride_length;
11117
11118     return(TNG_SUCCESS);
11119 }
11120
11121 tng_function_status DECLSPECDLLEXPORT tng_medium_stride_length_set
11122                     (tng_trajectory_t tng_data,
11123                      const int64_t len)
11124 {
11125     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11126
11127     if(len >= tng_data->long_stride_length)
11128     {
11129         return(TNG_FAILURE);
11130     }
11131     tng_data->medium_stride_length = len;
11132
11133     return(TNG_SUCCESS);
11134 }
11135
11136 tng_function_status DECLSPECDLLEXPORT tng_long_stride_length_get
11137                 (const tng_trajectory_t tng_data,
11138                  int64_t *len)
11139 {
11140     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11141     TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
11142
11143     *len = tng_data->long_stride_length;
11144
11145     return(TNG_SUCCESS);
11146 }
11147
11148 tng_function_status DECLSPECDLLEXPORT tng_long_stride_length_set
11149                 (tng_trajectory_t tng_data,
11150                  const int64_t len)
11151 {
11152     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11153
11154     if(len <= tng_data->medium_stride_length)
11155     {
11156         return(TNG_FAILURE);
11157     }
11158     tng_data->long_stride_length = len;
11159
11160     return(TNG_SUCCESS);
11161 }
11162
11163 tng_function_status DECLSPECDLLEXPORT tng_time_per_frame_get
11164                 (const tng_trajectory_t tng_data,
11165                  double *time)
11166 {
11167     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11168     TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
11169
11170     *time = tng_data->time_per_frame;
11171
11172     return(TNG_SUCCESS);
11173 }
11174
11175 tng_function_status DECLSPECDLLEXPORT tng_time_per_frame_set
11176                 (tng_trajectory_t tng_data,
11177                  const double time)
11178 {
11179     tng_trajectory_frame_set_t frame_set;
11180
11181     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11182     TNG_ASSERT(time >= 0, "TNG library: The time per frame must be >= 0.");
11183
11184     if(fabs(time - tng_data->time_per_frame) < 0.00001)
11185     {
11186         return(TNG_SUCCESS);
11187     }
11188
11189     frame_set = &tng_data->current_trajectory_frame_set;
11190
11191     /* If the current frame set is not finished write it to disk before
11192        changing time per frame. */
11193     if(tng_data->time_per_frame > 0 && frame_set->n_unwritten_frames > 0)
11194     {
11195         frame_set->n_frames = frame_set->n_unwritten_frames;
11196         tng_frame_set_write(tng_data, TNG_USE_HASH);
11197     }
11198     tng_data->time_per_frame = time;
11199
11200     return(TNG_SUCCESS);
11201 }
11202
11203 tng_function_status DECLSPECDLLEXPORT tng_input_file_len_get
11204                     (const tng_trajectory_t tng_data,
11205                      int64_t *len)
11206 {
11207     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11208     TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
11209
11210     *len = tng_data->input_file_len;
11211
11212     return(TNG_SUCCESS);
11213 }
11214
11215 tng_function_status DECLSPECDLLEXPORT tng_num_frames_get
11216                     (const tng_trajectory_t tng_data,
11217                      int64_t *n)
11218 {
11219     tng_gen_block_t block;
11220     tng_function_status stat;
11221     long file_pos;
11222     int64_t last_file_pos, first_frame, n_frames;
11223
11224     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11225     TNG_ASSERT(tng_data->input_file, "TNG library: An input file must be open to find the next frame set");
11226     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11227
11228     file_pos = ftell(tng_data->input_file);
11229     last_file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
11230
11231     if(last_file_pos <= 0)
11232     {
11233         return(TNG_FAILURE);
11234     }
11235
11236     tng_block_init(&block);
11237     fseek(tng_data->input_file,
11238           (long)last_file_pos,
11239           SEEK_SET);
11240     /* Read block headers first to see that a frame set block is found. */
11241     stat = tng_block_header_read(tng_data, block);
11242     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11243     {
11244         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", last_file_pos,
11245                 __FILE__, __LINE__);
11246         tng_block_destroy(&block);
11247         return(TNG_FAILURE);
11248     }
11249     tng_block_destroy(&block);
11250
11251     if(fread(&first_frame, sizeof(int64_t), 1, tng_data->input_file) == 0)
11252     {
11253         fprintf(stderr, "TNG library: Cannot read first frame of frame set. %s: %d\n",
11254                __FILE__, __LINE__);
11255         return(TNG_CRITICAL);
11256     }
11257     if(fread(&n_frames, sizeof(int64_t), 1, tng_data->input_file) == 0)
11258     {
11259         fprintf(stderr, "TNG library: Cannot read n frames of frame set. %s: %d\n",
11260                __FILE__, __LINE__);
11261         return(TNG_CRITICAL);
11262     }
11263     fseek(tng_data->input_file, file_pos, SEEK_SET);
11264
11265     *n = first_frame + n_frames;
11266
11267     return(TNG_SUCCESS);
11268 }
11269
11270 tng_function_status DECLSPECDLLEXPORT tng_compression_precision_get
11271                 (const tng_trajectory_t tng_data,
11272                  double *precision)
11273 {
11274     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11275
11276     *precision = tng_data->compression_precision;
11277
11278     return(TNG_SUCCESS);
11279 }
11280
11281 tng_function_status DECLSPECDLLEXPORT tng_compression_precision_set
11282                 (tng_trajectory_t tng_data,
11283                  const double precision)
11284 {
11285     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11286
11287     tng_data->compression_precision = precision;
11288
11289     return(TNG_SUCCESS);
11290 }
11291
11292 tng_function_status DECLSPECDLLEXPORT tng_implicit_num_particles_set
11293                 (tng_trajectory_t tng_data,
11294                  const int64_t n)
11295 {
11296     tng_molecule_t mol;
11297     tng_chain_t chain;
11298     tng_residue_t res;
11299     tng_atom_t atom;
11300     tng_function_status stat;
11301     int64_t diff, n_mod, n_impl;
11302
11303     TNG_ASSERT(n >= 0, "TNG library: The number of molecules must be >= 0");
11304
11305     diff = n - tng_data->n_particles;
11306
11307     stat = tng_molecule_find(tng_data, "TNG_IMPLICIT_MOL", -1, &mol);
11308     if(stat == TNG_SUCCESS)
11309     {
11310         if(tng_molecule_cnt_get(tng_data, mol, &n_impl) != TNG_SUCCESS)
11311         {
11312             fprintf(stderr, "TNG library: Cannot get the number of implicit molecules. %s: %d\n",
11313                     __FILE__, __LINE__);
11314             return(TNG_FAILURE);
11315         }
11316         diff -= n_impl * mol->n_atoms;
11317     }
11318
11319     if(diff == 0)
11320     {
11321         if(stat == TNG_SUCCESS)
11322         {
11323             stat = tng_molecule_cnt_set(tng_data, mol, 0);
11324             return(stat);
11325         }
11326         return(TNG_SUCCESS);
11327     }
11328     else if(diff < 0)
11329     {
11330         fprintf(stderr, "TNG library: Already more actual particles than requested implicit ");
11331         fprintf(stderr, "particle count.\n");
11332         fprintf(stderr, "TNG library: Cannot set implicit particle count. %s: %d\n",
11333                 __FILE__, __LINE__);
11334         /* FIXME: Should we set the count of all other molecules to 0 and add
11335          * implicit molecules? */
11336         return(TNG_FAILURE);
11337     }
11338     if(stat != TNG_SUCCESS)
11339     {
11340         stat = tng_molecule_add(tng_data,
11341                                 "TNG_IMPLICIT_MOL",
11342                                 &mol);
11343         if(stat != TNG_SUCCESS)
11344         {
11345             return(stat);
11346         }
11347         stat = tng_molecule_chain_add(tng_data, mol, "", &chain);
11348         if(stat != TNG_SUCCESS)
11349         {
11350             return(stat);
11351         }
11352         stat = tng_chain_residue_add(tng_data, chain, "", &res);
11353         if(stat != TNG_SUCCESS)
11354         {
11355             return(stat);
11356         }
11357         stat = tng_residue_atom_add(tng_data, res, "", "", &atom);
11358         if(stat != TNG_SUCCESS)
11359         {
11360             return(stat);
11361         }
11362     }
11363     else
11364     {
11365         if(mol->n_atoms > 1)
11366         {
11367             n_mod = diff % mol->n_atoms;
11368             if(n_mod != 0)
11369             {
11370                 fprintf(stderr, "TNG library: Number of atoms in implicit molecule ");
11371                 fprintf(stderr, "not compatible with requested implicit particle cnt.\n");
11372                 fprintf(stderr, "TNG library: Cannot set implicit particle count. %s: %d\n",
11373                         __FILE__, __LINE__);
11374                 return(TNG_FAILURE);
11375             }
11376             diff /= mol->n_atoms;
11377         }
11378     }
11379     stat = tng_molecule_cnt_set(tng_data, mol, diff);
11380
11381     return(stat);
11382 }
11383
11384 tng_function_status DECLSPECDLLEXPORT tng_num_particles_get
11385                 (const tng_trajectory_t tng_data,
11386                  int64_t *n)
11387 {
11388     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11389     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11390
11391     if(tng_data->var_num_atoms_flag == TNG_CONSTANT_N_ATOMS)
11392     {
11393         *n = tng_data->n_particles;
11394     }
11395     else
11396     {
11397         *n = tng_data->current_trajectory_frame_set.n_particles;
11398     }
11399
11400     return(TNG_SUCCESS);
11401 }
11402
11403 tng_function_status DECLSPECDLLEXPORT tng_num_particles_variable_get
11404                 (const tng_trajectory_t tng_data,
11405                  char *variable)
11406 {
11407     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11408     TNG_ASSERT(variable, "TNG library: variable must not be a NULL pointer");
11409
11410     *variable = tng_data->var_num_atoms_flag;
11411
11412     return(TNG_SUCCESS);
11413 }
11414
11415 tng_function_status DECLSPECDLLEXPORT tng_num_molecule_types_get
11416                     (const tng_trajectory_t tng_data,
11417                      int64_t *n)
11418 {
11419     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11420     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11421
11422     *n = tng_data->n_molecules;
11423
11424     return(TNG_SUCCESS);
11425 }
11426
11427 tng_function_status DECLSPECDLLEXPORT tng_num_molecules_get
11428                     (const tng_trajectory_t tng_data,
11429                      int64_t *n)
11430 {
11431     int64_t *cnt_list = 0, cnt = 0, i;
11432
11433     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11434     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11435
11436     tng_molecule_cnt_list_get(tng_data, &cnt_list);
11437
11438     if(!cnt_list)
11439     {
11440         return(TNG_FAILURE);
11441     }
11442
11443     for(i = 0; i < tng_data->n_molecules; i++)
11444     {
11445         cnt += cnt_list[i];
11446     }
11447
11448     *n = cnt;
11449
11450     return(TNG_SUCCESS);
11451 }
11452
11453 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_list_get
11454                 (const tng_trajectory_t tng_data,
11455                  int64_t **mol_cnt_list)
11456 {
11457     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11458
11459     if(tng_data->var_num_atoms_flag)
11460     {
11461         *mol_cnt_list = tng_data->current_trajectory_frame_set.
11462                        molecule_cnt_list;
11463     }
11464     else
11465     {
11466         *mol_cnt_list = tng_data->molecule_cnt_list;
11467     }
11468     if(*mol_cnt_list == 0)
11469     {
11470         return(TNG_FAILURE);
11471     }
11472     return(TNG_SUCCESS);
11473 }
11474
11475 tng_function_status DECLSPECDLLEXPORT tng_distance_unit_exponential_get
11476                 (const tng_trajectory_t tng_data,
11477                  int64_t *exp)
11478 {
11479     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11480     TNG_ASSERT(exp, "TNG library: exp must not be a NULL pointer");
11481
11482     *exp = tng_data->distance_unit_exponential;
11483
11484     return(TNG_SUCCESS);
11485 }
11486
11487 tng_function_status DECLSPECDLLEXPORT tng_distance_unit_exponential_set
11488                 (const tng_trajectory_t tng_data,
11489                  const int64_t exp)
11490 {
11491     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11492
11493     tng_data->distance_unit_exponential = exp;
11494
11495     return(TNG_SUCCESS);
11496 }
11497
11498 tng_function_status DECLSPECDLLEXPORT tng_num_frames_per_frame_set_get
11499                 (const tng_trajectory_t tng_data,
11500                  int64_t *n)
11501 {
11502     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11503     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11504
11505     *n = tng_data->frame_set_n_frames;
11506
11507     return(TNG_SUCCESS);
11508 }
11509
11510 tng_function_status DECLSPECDLLEXPORT tng_num_frames_per_frame_set_set
11511                 (const tng_trajectory_t tng_data,
11512                  const int64_t n)
11513 {
11514     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11515
11516     tng_data->frame_set_n_frames = n;
11517
11518     return(TNG_SUCCESS);
11519 }
11520
11521 tng_function_status DECLSPECDLLEXPORT tng_num_frame_sets_get
11522                 (const tng_trajectory_t tng_data,
11523                  int64_t *n)
11524 {
11525     int64_t long_stride_length, medium_stride_length;
11526     long file_pos, orig_frame_set_file_pos;
11527     tng_trajectory_frame_set_t frame_set;
11528     struct tng_trajectory_frame_set orig_frame_set;
11529     tng_gen_block_t block;
11530     tng_function_status stat;
11531     int64_t cnt = 0;
11532
11533     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11534     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11535
11536     orig_frame_set = tng_data->current_trajectory_frame_set;
11537
11538     frame_set = &tng_data->current_trajectory_frame_set;
11539
11540     orig_frame_set_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
11541     file_pos = (long)tng_data->first_trajectory_frame_set_input_file_pos;
11542
11543     if(file_pos < 0)
11544     {
11545         *n = tng_data->n_trajectory_frame_sets = cnt;
11546         return(TNG_SUCCESS);
11547     }
11548
11549     tng_block_init(&block);
11550     fseek(tng_data->input_file,
11551           file_pos,
11552           SEEK_SET);
11553     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
11554     /* Read block headers first to see what block is found. */
11555     stat = tng_block_header_read(tng_data, block);
11556     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11557     {
11558         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n", file_pos,
11559                 __FILE__, __LINE__);
11560         tng_block_destroy(&block);
11561         return(TNG_CRITICAL);
11562     }
11563
11564     if(tng_block_read_next(tng_data, block,
11565                         TNG_SKIP_HASH) != TNG_SUCCESS)
11566     {
11567         tng_block_destroy(&block);
11568         return(TNG_CRITICAL);
11569     }
11570
11571     ++cnt;
11572
11573     long_stride_length = tng_data->long_stride_length;
11574     medium_stride_length = tng_data->medium_stride_length;
11575
11576     /* Take long steps forward until a long step forward would be too long or
11577      * the last frame set is found */
11578     file_pos = (long)frame_set->long_stride_next_frame_set_file_pos;
11579     while(file_pos > 0)
11580     {
11581         if(file_pos > 0)
11582         {
11583             cnt += long_stride_length;
11584             fseek(tng_data->input_file, file_pos, 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 %ld. %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         file_pos = (long)frame_set->long_stride_next_frame_set_file_pos;
11603     }
11604
11605     /* Take medium steps forward until a medium step forward would be too long
11606      * or the last frame set is found */
11607     file_pos = (long)frame_set->medium_stride_next_frame_set_file_pos;
11608     while(file_pos > 0)
11609     {
11610         if(file_pos > 0)
11611         {
11612             cnt += medium_stride_length;
11613             fseek(tng_data->input_file,
11614                   file_pos,
11615                   SEEK_SET);
11616             /* Read block headers first to see what block is found. */
11617             stat = tng_block_header_read(tng_data, block);
11618             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11619             {
11620                 fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
11621                        file_pos, __FILE__, __LINE__);
11622                 tng_block_destroy(&block);
11623                 return(TNG_CRITICAL);
11624             }
11625
11626             if(tng_block_read_next(tng_data, block,
11627                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11628             {
11629                 tng_block_destroy(&block);
11630                 return(TNG_CRITICAL);
11631             }
11632         }
11633         file_pos = (long)frame_set->medium_stride_next_frame_set_file_pos;
11634     }
11635
11636     /* Take one step forward until the last frame set is found */
11637     file_pos = (long)frame_set->next_frame_set_file_pos;
11638     while(file_pos > 0)
11639     {
11640         if(file_pos > 0)
11641         {
11642             ++cnt;
11643             fseek(tng_data->input_file,
11644                   file_pos,
11645                   SEEK_SET);
11646             /* Read block headers first to see what block is found. */
11647             stat = tng_block_header_read(tng_data, block);
11648             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11649             {
11650                 fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
11651                        file_pos, __FILE__, __LINE__);
11652                 tng_block_destroy(&block);
11653                 return(TNG_CRITICAL);
11654             }
11655
11656             if(tng_block_read_next(tng_data, block,
11657                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11658             {
11659                 tng_block_destroy(&block);
11660                 return(TNG_CRITICAL);
11661             }
11662         }
11663         file_pos = (long)frame_set->next_frame_set_file_pos;
11664     }
11665
11666     tng_block_destroy(&block);
11667
11668     *n = tng_data->n_trajectory_frame_sets = cnt;
11669
11670     *frame_set = orig_frame_set;
11671
11672     fseek(tng_data->input_file,
11673           (long)tng_data->first_trajectory_frame_set_input_file_pos,
11674           SEEK_SET);
11675
11676     tng_data->current_trajectory_frame_set_input_file_pos = orig_frame_set_file_pos;
11677
11678     return(TNG_SUCCESS);
11679 }
11680
11681 tng_function_status DECLSPECDLLEXPORT tng_current_frame_set_get
11682                 (const tng_trajectory_t tng_data,
11683                  tng_trajectory_frame_set_t *frame_set_p)
11684 {
11685     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11686
11687     *frame_set_p = &tng_data->current_trajectory_frame_set;
11688
11689     return(TNG_SUCCESS);
11690 }
11691
11692 tng_function_status DECLSPECDLLEXPORT tng_frame_set_nr_find
11693                 (tng_trajectory_t tng_data,
11694                  const int64_t nr)
11695 {
11696     int64_t long_stride_length, medium_stride_length;
11697     int64_t file_pos, curr_nr = 0, n_frame_sets;
11698     tng_trajectory_frame_set_t frame_set;
11699     tng_gen_block_t block;
11700     tng_function_status stat;
11701
11702     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11703     TNG_ASSERT(nr >= 0, "The frame set number (nr) must be >= 0");
11704
11705     frame_set = &tng_data->current_trajectory_frame_set;
11706
11707     stat = tng_num_frame_sets_get(tng_data, &n_frame_sets);
11708
11709     if(stat != TNG_SUCCESS)
11710     {
11711         return(stat);
11712     }
11713
11714     if(nr >= n_frame_sets)
11715     {
11716         return(TNG_FAILURE);
11717     }
11718
11719     long_stride_length = tng_data->long_stride_length;
11720     medium_stride_length = tng_data->medium_stride_length;
11721
11722     /* FIXME: The frame set number of the current frame set is not stored */
11723
11724     if(nr < n_frame_sets - 1 - nr)
11725     {
11726         /* Start from the beginning */
11727         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
11728     }
11729     else
11730     {
11731         /* Start from the end */
11732         file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
11733         curr_nr = n_frame_sets - 1;
11734     }
11735     if(file_pos <= 0)
11736     {
11737         return(TNG_FAILURE);
11738     }
11739
11740     tng_block_init(&block);
11741     fseek(tng_data->input_file,
11742           (long)file_pos,
11743           SEEK_SET);
11744     tng_data->current_trajectory_frame_set_input_file_pos = (long)file_pos;
11745     /* Read block headers first to see what block is found. */
11746     stat = tng_block_header_read(tng_data, block);
11747     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11748     {
11749         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", file_pos,
11750                 __FILE__, __LINE__);
11751         tng_block_destroy(&block);
11752         return(TNG_CRITICAL);
11753     }
11754
11755     if(tng_block_read_next(tng_data, block,
11756                         TNG_SKIP_HASH) != TNG_SUCCESS)
11757     {
11758         tng_block_destroy(&block);
11759         return(TNG_CRITICAL);
11760     }
11761
11762     if(curr_nr == nr)
11763     {
11764         tng_block_destroy(&block);
11765         return(TNG_SUCCESS);
11766     }
11767
11768     file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
11769
11770     /* Take long steps forward until a long step forward would be too long or
11771      * the right frame set is found */
11772     while(file_pos > 0 && curr_nr + long_stride_length <= nr)
11773     {
11774         file_pos = frame_set->long_stride_next_frame_set_file_pos;
11775         if(file_pos > 0)
11776         {
11777             curr_nr += long_stride_length;
11778             fseek(tng_data->input_file, (long)file_pos, SEEK_SET);
11779             /* Read block headers first to see what block is found. */
11780             stat = tng_block_header_read(tng_data, block);
11781             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11782             {
11783                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11784                        file_pos,  __FILE__, __LINE__);
11785                 tng_block_destroy(&block);
11786                 return(TNG_CRITICAL);
11787             }
11788
11789             if(tng_block_read_next(tng_data, block,
11790                                    TNG_SKIP_HASH) != TNG_SUCCESS)
11791             {
11792                 tng_block_destroy(&block);
11793                 return(TNG_CRITICAL);
11794             }
11795             if(curr_nr == nr)
11796             {
11797                 tng_block_destroy(&block);
11798                 return(TNG_SUCCESS);
11799             }
11800         }
11801     }
11802
11803     /* Take medium steps forward until a medium step forward would be too long
11804      * or the right frame set is found */
11805     while(file_pos > 0 && curr_nr + medium_stride_length <= nr)
11806     {
11807         file_pos = frame_set->medium_stride_next_frame_set_file_pos;
11808         if(file_pos > 0)
11809         {
11810             curr_nr += medium_stride_length;
11811             fseek(tng_data->input_file,
11812                   (long)file_pos,
11813                   SEEK_SET);
11814             /* Read block headers first to see what block is found. */
11815             stat = tng_block_header_read(tng_data, block);
11816             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11817             {
11818                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11819                        file_pos, __FILE__, __LINE__);
11820                 tng_block_destroy(&block);
11821                 return(TNG_CRITICAL);
11822             }
11823
11824             if(tng_block_read_next(tng_data, block,
11825                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11826             {
11827                 tng_block_destroy(&block);
11828                 return(TNG_CRITICAL);
11829             }
11830             if(curr_nr == nr)
11831             {
11832                 tng_block_destroy(&block);
11833                 return(TNG_SUCCESS);
11834             }
11835         }
11836     }
11837
11838     /* Take one step forward until the right frame set is found */
11839     while(file_pos > 0 && curr_nr < nr)
11840     {
11841         file_pos = frame_set->next_frame_set_file_pos;
11842
11843         if(file_pos > 0)
11844         {
11845             ++curr_nr;
11846             fseek(tng_data->input_file,
11847                   (long)file_pos,
11848                   SEEK_SET);
11849             /* Read block headers first to see what block is found. */
11850             stat = tng_block_header_read(tng_data, block);
11851             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11852             {
11853                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11854                        file_pos, __FILE__, __LINE__);
11855                 tng_block_destroy(&block);
11856                 return(TNG_CRITICAL);
11857             }
11858
11859             if(tng_block_read_next(tng_data, block,
11860                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11861             {
11862                 tng_block_destroy(&block);
11863                 return(TNG_CRITICAL);
11864             }
11865             if(curr_nr == nr)
11866             {
11867                 tng_block_destroy(&block);
11868                 return(TNG_SUCCESS);
11869             }
11870         }
11871     }
11872
11873     /* Take long steps backward until a long step backward would be too long
11874      * or the right frame set is found */
11875     while(file_pos > 0 && curr_nr - long_stride_length >= nr)
11876     {
11877         file_pos = frame_set->long_stride_prev_frame_set_file_pos;
11878         if(file_pos > 0)
11879         {
11880             curr_nr -= long_stride_length;
11881             fseek(tng_data->input_file,
11882                   (long)file_pos,
11883                   SEEK_SET);
11884             /* Read block headers first to see what block is found. */
11885             stat = tng_block_header_read(tng_data, block);
11886             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11887             {
11888                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11889                        file_pos, __FILE__, __LINE__);
11890                 tng_block_destroy(&block);
11891                 return(TNG_CRITICAL);
11892             }
11893
11894             if(tng_block_read_next(tng_data, block,
11895                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11896             {
11897                 tng_block_destroy(&block);
11898                 return(TNG_CRITICAL);
11899             }
11900             if(curr_nr == nr)
11901             {
11902                 tng_block_destroy(&block);
11903                 return(TNG_SUCCESS);
11904             }
11905         }
11906     }
11907
11908     /* Take medium steps backward until a medium step backward would be too long
11909      * or the right frame set is found */
11910     while(file_pos > 0 && curr_nr - medium_stride_length >= nr)
11911     {
11912         file_pos = frame_set->medium_stride_prev_frame_set_file_pos;
11913         if(file_pos > 0)
11914         {
11915             curr_nr -= medium_stride_length;
11916             fseek(tng_data->input_file,
11917                   (long)file_pos,
11918                   SEEK_SET);
11919             /* Read block headers first to see what block is found. */
11920             stat = tng_block_header_read(tng_data, block);
11921             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11922             {
11923                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11924                        file_pos, __FILE__, __LINE__);
11925                 tng_block_destroy(&block);
11926                 return(TNG_CRITICAL);
11927             }
11928
11929             if(tng_block_read_next(tng_data, block,
11930                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11931             {
11932                 tng_block_destroy(&block);
11933                 return(TNG_CRITICAL);
11934             }
11935             if(curr_nr == nr)
11936             {
11937                 tng_block_destroy(&block);
11938                 return(TNG_SUCCESS);
11939             }
11940         }
11941     }
11942
11943     /* Take one step backward until the right frame set is found */
11944     while(file_pos > 0 && curr_nr > nr)
11945     {
11946         file_pos = frame_set->prev_frame_set_file_pos;
11947         if(file_pos > 0)
11948         {
11949             --curr_nr;
11950             fseek(tng_data->input_file,
11951                   (long)file_pos,
11952                   SEEK_SET);
11953             /* Read block headers first to see what block is found. */
11954             stat = tng_block_header_read(tng_data, block);
11955             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11956             {
11957                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11958                        file_pos, __FILE__, __LINE__);
11959                 tng_block_destroy(&block);
11960                 return(TNG_CRITICAL);
11961             }
11962
11963             if(tng_block_read_next(tng_data, block,
11964                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11965             {
11966                 tng_block_destroy(&block);
11967                 return(TNG_CRITICAL);
11968             }
11969             if(curr_nr == nr)
11970             {
11971                 tng_block_destroy(&block);
11972                 return(TNG_SUCCESS);
11973             }
11974         }
11975     }
11976
11977     /* If for some reason the current frame set is not yet found,
11978      * take one step forward until the right frame set is found */
11979     while(file_pos > 0 && curr_nr < nr)
11980     {
11981         file_pos = frame_set->next_frame_set_file_pos;
11982         if(file_pos > 0)
11983         {
11984             ++curr_nr;
11985             fseek(tng_data->input_file,
11986                   (long)file_pos,
11987                   SEEK_SET);
11988             /* Read block headers first to see what block is found. */
11989             stat = tng_block_header_read(tng_data, block);
11990             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11991             {
11992                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11993                        file_pos, __FILE__, __LINE__);
11994                 tng_block_destroy(&block);
11995                 return(TNG_CRITICAL);
11996             }
11997
11998             if(tng_block_read_next(tng_data, block,
11999                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12000             {
12001                 tng_block_destroy(&block);
12002                 return(TNG_CRITICAL);
12003             }
12004             if(curr_nr == nr)
12005             {
12006                 tng_block_destroy(&block);
12007                 return(TNG_SUCCESS);
12008             }
12009         }
12010     }
12011
12012     tng_block_destroy(&block);
12013     return(TNG_FAILURE);
12014 }
12015
12016 tng_function_status DECLSPECDLLEXPORT tng_frame_set_of_frame_find
12017                 (tng_trajectory_t tng_data,
12018                  const int64_t frame)
12019 {
12020     int64_t first_frame, last_frame, n_frames_per_frame_set;
12021     int64_t long_stride_length, medium_stride_length;
12022     int64_t file_pos, temp_frame, n_frames;
12023     tng_trajectory_frame_set_t frame_set;
12024     tng_gen_block_t block;
12025     tng_function_status stat;
12026
12027     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12028     TNG_ASSERT(frame >= 0, "TNG library: frame must be >= 0.");
12029
12030     frame_set = &tng_data->current_trajectory_frame_set;
12031
12032     tng_block_init(&block);
12033
12034     if(tng_data->current_trajectory_frame_set_input_file_pos < 0)
12035     {
12036         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
12037         fseek(tng_data->input_file,
12038                 (long)file_pos,
12039                 SEEK_SET);
12040         tng_data->current_trajectory_frame_set_input_file_pos = (long)file_pos;
12041         /* Read block headers first to see what block is found. */
12042         stat = tng_block_header_read(tng_data, block);
12043         if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12044         {
12045             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12046                     file_pos, __FILE__, __LINE__);
12047             tng_block_destroy(&block);
12048             return(TNG_CRITICAL);
12049         }
12050
12051         if(tng_block_read_next(tng_data, block,
12052                             TNG_SKIP_HASH) != TNG_SUCCESS)
12053         {
12054             tng_block_destroy(&block);
12055             return(TNG_CRITICAL);
12056         }
12057     }
12058
12059     first_frame = tng_max_i64(frame_set->first_frame, 0);
12060     last_frame = first_frame + frame_set->n_frames - 1;
12061     /* Is this the right frame set? */
12062     if(first_frame <= frame && frame <= last_frame)
12063     {
12064         tng_block_destroy(&block);
12065         return(TNG_SUCCESS);
12066     }
12067
12068     n_frames_per_frame_set = tng_data->frame_set_n_frames;
12069     long_stride_length = tng_data->long_stride_length;
12070     medium_stride_length = tng_data->medium_stride_length;
12071
12072     if(tng_first_frame_nr_of_next_frame_set_get(tng_data, &temp_frame) ==
12073        TNG_SUCCESS)
12074     {
12075         if(temp_frame - first_frame > n_frames_per_frame_set)
12076         {
12077             n_frames_per_frame_set = temp_frame - first_frame;
12078         }
12079     }
12080
12081     tng_num_frames_get(tng_data, &n_frames);
12082
12083     if(frame >= n_frames)
12084     {
12085         tng_block_destroy(&block);
12086         return(TNG_FAILURE);
12087     }
12088
12089     if(first_frame - frame >= frame ||
12090        frame - last_frame >
12091        tng_data->n_trajectory_frame_sets * n_frames_per_frame_set - frame)
12092     {
12093         /* Start from the beginning */
12094         if(first_frame - frame >= frame)
12095         {
12096             file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
12097
12098             if(file_pos <= 0)
12099             {
12100                 tng_block_destroy(&block);
12101                 return(TNG_FAILURE);
12102             }
12103         }
12104         /* Start from the end */
12105         else if(frame - first_frame > (n_frames - 1) - frame)
12106         {
12107             file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
12108
12109             /* If the last frame set position is not set start from the current
12110              * frame set, since it will be closer than the first frame set. */
12111         }
12112         /* Start from current */
12113         else
12114         {
12115             file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
12116         }
12117
12118         if(file_pos > 0)
12119         {
12120             fseek(tng_data->input_file,
12121                   (long)file_pos,
12122                   SEEK_SET);
12123             tng_data->current_trajectory_frame_set_input_file_pos = (long)file_pos;
12124             /* Read block headers first to see what block is found. */
12125             stat = tng_block_header_read(tng_data, block);
12126             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12127             {
12128                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12129                        file_pos, __FILE__, __LINE__);
12130                 tng_block_destroy(&block);
12131                 return(TNG_CRITICAL);
12132             }
12133
12134             if(tng_block_read_next(tng_data, block,
12135                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12136             {
12137                 tng_block_destroy(&block);
12138                 return(TNG_CRITICAL);
12139             }
12140         }
12141     }
12142
12143     first_frame = tng_max_i64(frame_set->first_frame, 0);
12144     last_frame = first_frame + frame_set->n_frames - 1;
12145
12146     if(frame >= first_frame && frame <= last_frame)
12147     {
12148         tng_block_destroy(&block);
12149         return(TNG_SUCCESS);
12150     }
12151
12152     file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
12153
12154     /* Take long steps forward until a long step forward would be too long or
12155      * the right frame set is found */
12156     while(file_pos > 0 && first_frame + long_stride_length *
12157           n_frames_per_frame_set <= frame)
12158     {
12159         file_pos = frame_set->long_stride_next_frame_set_file_pos;
12160         if(file_pos > 0)
12161         {
12162             fseek(tng_data->input_file, (long)file_pos, SEEK_SET);
12163             /* Read block headers first to see what block is found. */
12164             stat = tng_block_header_read(tng_data, block);
12165             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12166             {
12167                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12168                        file_pos, __FILE__, __LINE__);
12169                 tng_block_destroy(&block);
12170                 return(TNG_CRITICAL);
12171             }
12172
12173             if(tng_block_read_next(tng_data, block,
12174                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12175             {
12176                 tng_block_destroy(&block);
12177                 return(TNG_CRITICAL);
12178             }
12179         }
12180         first_frame = tng_max_i64(frame_set->first_frame, 0);
12181         last_frame = first_frame + frame_set->n_frames - 1;
12182         if(frame >= first_frame && frame <= last_frame)
12183         {
12184             tng_block_destroy(&block);
12185             return(TNG_SUCCESS);
12186         }
12187     }
12188
12189     /* Take medium steps forward until a medium step forward would be too long
12190      * or the right frame set is found */
12191     while(file_pos > 0 && first_frame + medium_stride_length *
12192           n_frames_per_frame_set <= frame)
12193     {
12194         file_pos = frame_set->medium_stride_next_frame_set_file_pos;
12195         if(file_pos > 0)
12196         {
12197             fseek(tng_data->input_file,
12198                   (long)file_pos,
12199                   SEEK_SET);
12200             /* Read block headers first to see what block is found. */
12201             stat = tng_block_header_read(tng_data, block);
12202             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12203             {
12204                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12205                        file_pos, __FILE__, __LINE__);
12206                 tng_block_destroy(&block);
12207                 return(TNG_CRITICAL);
12208             }
12209
12210             if(tng_block_read_next(tng_data, block,
12211                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12212             {
12213                 tng_block_destroy(&block);
12214                 return(TNG_CRITICAL);
12215             }
12216         }
12217         first_frame = tng_max_i64(frame_set->first_frame, 0);
12218         last_frame = first_frame + frame_set->n_frames - 1;
12219         if(frame >= first_frame && frame <= last_frame)
12220         {
12221             tng_block_destroy(&block);
12222             return(TNG_SUCCESS);
12223         }
12224     }
12225
12226     /* Take one step forward until the right frame set is found */
12227     while(file_pos > 0 && first_frame < frame && last_frame < frame)
12228     {
12229         file_pos = frame_set->next_frame_set_file_pos;
12230         if(file_pos > 0)
12231         {
12232             fseek(tng_data->input_file,
12233                   (long)file_pos,
12234                   SEEK_SET);
12235             /* Read block headers first to see what block is found. */
12236             stat = tng_block_header_read(tng_data, block);
12237             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12238             {
12239                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12240                        file_pos, __FILE__, __LINE__);
12241                 tng_block_destroy(&block);
12242                 return(TNG_CRITICAL);
12243             }
12244
12245             if(tng_block_read_next(tng_data, block,
12246                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12247             {
12248                 tng_block_destroy(&block);
12249                 return(TNG_CRITICAL);
12250             }
12251         }
12252         first_frame = tng_max_i64(frame_set->first_frame, 0);
12253         last_frame = first_frame + frame_set->n_frames - 1;
12254         if(frame >= first_frame && frame <= last_frame)
12255         {
12256             tng_block_destroy(&block);
12257             return(TNG_SUCCESS);
12258         }
12259     }
12260
12261     /* Take long steps backward until a long step backward would be too long
12262      * or the right frame set is found */
12263     while(file_pos > 0 && first_frame - long_stride_length *
12264           n_frames_per_frame_set >= frame)
12265     {
12266         file_pos = frame_set->long_stride_prev_frame_set_file_pos;
12267         if(file_pos > 0)
12268         {
12269             fseek(tng_data->input_file,
12270                   (long)file_pos,
12271                   SEEK_SET);
12272             /* Read block headers first to see what block is found. */
12273             stat = tng_block_header_read(tng_data, block);
12274             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12275             {
12276                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12277                        file_pos, __FILE__, __LINE__);
12278                 tng_block_destroy(&block);
12279                 return(TNG_CRITICAL);
12280             }
12281
12282             if(tng_block_read_next(tng_data, block,
12283                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12284             {
12285                 tng_block_destroy(&block);
12286                 return(TNG_CRITICAL);
12287             }
12288         }
12289         first_frame = tng_max_i64(frame_set->first_frame, 0);
12290         last_frame = first_frame + frame_set->n_frames - 1;
12291         if(frame >= first_frame && frame <= last_frame)
12292         {
12293             tng_block_destroy(&block);
12294             return(TNG_SUCCESS);
12295         }
12296     }
12297
12298     /* Take medium steps backward until a medium step backward would be too long
12299      * or the right frame set is found */
12300     while(file_pos > 0 && first_frame - medium_stride_length *
12301           n_frames_per_frame_set >= frame)
12302     {
12303         file_pos = frame_set->medium_stride_prev_frame_set_file_pos;
12304         if(file_pos > 0)
12305         {
12306             fseek(tng_data->input_file,
12307                   (long)file_pos,
12308                   SEEK_SET);
12309             /* Read block headers first to see what block is found. */
12310             stat = tng_block_header_read(tng_data, block);
12311             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12312             {
12313                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12314                        file_pos, __FILE__, __LINE__);
12315                 tng_block_destroy(&block);
12316                 return(TNG_CRITICAL);
12317             }
12318
12319             if(tng_block_read_next(tng_data, block,
12320                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12321             {
12322                 tng_block_destroy(&block);
12323                 return(TNG_CRITICAL);
12324             }
12325         }
12326         first_frame = tng_max_i64(frame_set->first_frame, 0);
12327         last_frame = first_frame + frame_set->n_frames - 1;
12328         if(frame >= first_frame && frame <= last_frame)
12329         {
12330             tng_block_destroy(&block);
12331             return(TNG_SUCCESS);
12332         }
12333     }
12334
12335     /* Take one step backward until the right frame set is found */
12336     while(file_pos > 0 && first_frame > frame && last_frame > frame)
12337     {
12338         file_pos = frame_set->prev_frame_set_file_pos;
12339         if(file_pos > 0)
12340         {
12341             fseek(tng_data->input_file,
12342                   (long)file_pos,
12343                   SEEK_SET);
12344             /* Read block headers first to see what block is found. */
12345             stat = tng_block_header_read(tng_data, block);
12346             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12347             {
12348                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12349                        file_pos, __FILE__, __LINE__);
12350                 tng_block_destroy(&block);
12351                 return(TNG_CRITICAL);
12352             }
12353
12354             if(tng_block_read_next(tng_data, block,
12355                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12356             {
12357                 tng_block_destroy(&block);
12358                 return(TNG_CRITICAL);
12359             }
12360         }
12361         first_frame = tng_max_i64(frame_set->first_frame, 0);
12362         last_frame = first_frame + frame_set->n_frames - 1;
12363         if(frame >= first_frame && frame <= last_frame)
12364         {
12365             tng_block_destroy(&block);
12366             return(TNG_SUCCESS);
12367         }
12368     }
12369
12370     /* If for some reason the current frame set is not yet found,
12371      * take one step forward until the right frame set is found */
12372     while(file_pos > 0 && first_frame < frame && last_frame < frame)
12373     {
12374         file_pos = frame_set->next_frame_set_file_pos;
12375         if(file_pos > 0)
12376         {
12377             fseek(tng_data->input_file,
12378                   (long)file_pos,
12379                   SEEK_SET);
12380             /* Read block headers first to see what block is found. */
12381             stat = tng_block_header_read(tng_data, block);
12382             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12383             {
12384                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12385                        file_pos, __FILE__, __LINE__);
12386                 tng_block_destroy(&block);
12387                 return(TNG_CRITICAL);
12388             }
12389
12390             if(tng_block_read_next(tng_data, block,
12391                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12392             {
12393                 tng_block_destroy(&block);
12394                 return(TNG_CRITICAL);
12395             }
12396         }
12397         first_frame = tng_max_i64(frame_set->first_frame, 0);
12398         last_frame = first_frame + frame_set->n_frames - 1;
12399         if(frame >= first_frame && frame <= last_frame)
12400         {
12401             tng_block_destroy(&block);
12402             return(TNG_SUCCESS);
12403         }
12404     }
12405
12406     tng_block_destroy(&block);
12407     return(TNG_FAILURE);
12408 }
12409
12410 tng_function_status DECLSPECDLLEXPORT tng_frame_set_next_frame_set_file_pos_get
12411                 (const tng_trajectory_t tng_data,
12412                  const tng_trajectory_frame_set_t frame_set,
12413                  int64_t *pos)
12414 {
12415     (void)tng_data;
12416
12417     TNG_ASSERT(frame_set, "TNG library: frame_set not initialised before accessing data.");
12418     TNG_ASSERT(pos, "TNG library: pos must not be a NULL pointer");
12419
12420     *pos = frame_set->next_frame_set_file_pos;
12421
12422     return(TNG_SUCCESS);
12423 }
12424
12425 tng_function_status DECLSPECDLLEXPORT tng_frame_set_prev_frame_set_file_pos_get
12426                 (const tng_trajectory_t tng_data,
12427                  const tng_trajectory_frame_set_t frame_set,
12428                  int64_t *pos)
12429 {
12430     (void)tng_data;
12431
12432     TNG_ASSERT(frame_set, "TNG library: frame_set not initialised before accessing data.");
12433     TNG_ASSERT(pos, "TNG library: pos must not be a NULL pointer");
12434
12435     *pos = frame_set->prev_frame_set_file_pos;
12436
12437     return(TNG_SUCCESS);
12438 }
12439
12440 tng_function_status DECLSPECDLLEXPORT tng_frame_set_frame_range_get
12441                 (const tng_trajectory_t tng_data,
12442                  const tng_trajectory_frame_set_t frame_set,
12443                  int64_t *first_frame,
12444                  int64_t *last_frame)
12445 {
12446     (void)tng_data;
12447
12448     TNG_ASSERT(first_frame, "TNG library: first_frame must not be a NULL pointer");
12449     TNG_ASSERT(last_frame, "TNG library: last_frame must not be a NULL pointer");
12450     TNG_ASSERT(frame_set, "TNG library: frame_set must not be a NULL pointer");
12451
12452     *first_frame = frame_set->first_frame;
12453     *last_frame = *first_frame + frame_set->n_frames - 1;
12454
12455     return(TNG_SUCCESS);
12456 }
12457
12458 /** Translate from the particle numbering used in a frame set to the real
12459  *  particle numbering - used in the molecule description.
12460  * @param frame_set is the frame_set containing the mappings to use.
12461  * @param local is the index number of the atom in this frame set
12462  * @param real is set to the index of the atom in the molecular system.
12463  * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the mapping
12464  * cannot be found.
12465  */
12466 static TNG_INLINE tng_function_status tng_particle_mapping_get_real_particle
12467                 (const tng_trajectory_frame_set_t frame_set,
12468                  const int64_t local,
12469                  int64_t *real)
12470 {
12471     int64_t i, n_blocks = frame_set->n_mapping_blocks, first;
12472     tng_particle_mapping_t mapping;
12473     if(n_blocks <= 0)
12474     {
12475         *real = local;
12476         return(TNG_SUCCESS);
12477     }
12478     for(i = 0; i < n_blocks; i++)
12479     {
12480         mapping = &frame_set->mappings[i];
12481         first = mapping->num_first_particle;
12482         if(local < first ||
12483            local >= first + mapping->n_particles)
12484         {
12485             continue;
12486         }
12487         *real = mapping->real_particle_numbers[local-first];
12488         return(TNG_SUCCESS);
12489     }
12490     *real = local;
12491     return(TNG_FAILURE);
12492 }
12493
12494 /** Translate from the real particle numbering to the particle numbering
12495  *  used in a frame set.
12496  * @param frame_set is the frame_set containing the mappings to use.
12497  * @param real is the index number of the atom in the molecular system.
12498  * @param local is set to the index of the atom in this frame set.
12499  * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the mapping
12500  * cannot be found.
12501  */
12502 /*static TNG_INLINE tng_function_status tng_particle_mapping_get_local_particle
12503                 (const tng_trajectory_frame_set_t frame_set,
12504                  const int64_t real,
12505                  int64_t *local)
12506 {
12507     int64_t i, j, n_blocks = frame_set->n_mapping_blocks;
12508     tng_particle_mapping_t mapping;
12509     if(n_blocks <= 0)
12510     {
12511         *local = real;
12512         return(TNG_SUCCESS);
12513     }
12514     for(i = 0; i < n_blocks; i++)
12515     {
12516         mapping = &frame_set->mappings[i];
12517         for(j = mapping->n_particles; j--;)
12518         {
12519             if(mapping->real_particle_numbers[j] == real)
12520             {
12521                 *local = j;
12522                 return(TNG_SUCCESS);
12523             }
12524         }
12525     }
12526     return(TNG_FAILURE);
12527 }
12528 */
12529
12530 static tng_function_status tng_file_headers_len_get
12531                 (tng_trajectory_t tng_data,
12532                  int64_t *len)
12533 {
12534     int64_t orig_pos;
12535     tng_gen_block_t block;
12536
12537     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12538
12539     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12540     {
12541         return(TNG_CRITICAL);
12542     }
12543
12544     *len = 0;
12545
12546     orig_pos = ftell(tng_data->input_file);
12547
12548     if(!tng_data->input_file_len)
12549     {
12550         fseek(tng_data->input_file, 0, SEEK_END);
12551         tng_data->input_file_len = ftell(tng_data->input_file);
12552     }
12553     fseek(tng_data->input_file, 0, SEEK_SET);
12554
12555     tng_block_init(&block);
12556     /* Read through the headers of non-trajectory blocks (they come before the
12557      * trajectory blocks in the file) */
12558     while (*len < tng_data->input_file_len &&
12559            tng_block_header_read(tng_data, block) != TNG_CRITICAL &&
12560            block->id != -1 &&
12561            block->id != TNG_TRAJECTORY_FRAME_SET)
12562     {
12563         *len += block->header_contents_size + block->block_contents_size;
12564         fseek(tng_data->input_file, block->block_contents_size, SEEK_CUR);
12565     }
12566
12567     fseek(tng_data->input_file, orig_pos, SEEK_SET);
12568
12569     tng_block_destroy(&block);
12570
12571     return(TNG_SUCCESS);
12572 }
12573
12574 tng_function_status DECLSPECDLLEXPORT tng_file_headers_read
12575                 (tng_trajectory_t tng_data,
12576                  const char hash_mode)
12577 {
12578     int64_t prev_pos = 0;
12579     tng_gen_block_t block;
12580
12581     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12582
12583     tng_data->n_trajectory_frame_sets = 0;
12584
12585     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12586     {
12587         return(TNG_CRITICAL);
12588     }
12589
12590     if(!tng_data->input_file_len)
12591     {
12592         fseek(tng_data->input_file, 0, SEEK_END);
12593         tng_data->input_file_len = ftell(tng_data->input_file);
12594     }
12595     fseek(tng_data->input_file, 0, SEEK_SET);
12596
12597     tng_block_init(&block);
12598     /* Non trajectory blocks (they come before the trajectory
12599      * blocks in the file) */
12600     while (prev_pos < tng_data->input_file_len &&
12601            tng_block_header_read(tng_data, block) != TNG_CRITICAL &&
12602            block->id != -1 &&
12603            block->id != TNG_TRAJECTORY_FRAME_SET)
12604     {
12605         tng_block_read_next(tng_data, block, hash_mode);
12606         prev_pos = ftell(tng_data->input_file);
12607     }
12608
12609     /* Go back if a trajectory block was encountered */
12610     if(block->id == TNG_TRAJECTORY_FRAME_SET)
12611     {
12612         fseek(tng_data->input_file, prev_pos, SEEK_SET);
12613     }
12614
12615     tng_block_destroy(&block);
12616
12617     return(TNG_SUCCESS);
12618 }
12619
12620 tng_function_status DECLSPECDLLEXPORT tng_file_headers_write
12621                 (tng_trajectory_t tng_data,
12622                  const char hash_mode)
12623 {
12624     int i;
12625     int64_t len, orig_len, tot_len = 0, data_start_pos;
12626     tng_function_status stat;
12627     tng_gen_block_t block;
12628
12629     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12630
12631     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
12632     {
12633         return(TNG_CRITICAL);
12634     }
12635
12636     if(tng_data->n_trajectory_frame_sets > 0)
12637     {
12638         stat = tng_file_headers_len_get(tng_data, &orig_len);
12639         if(stat != TNG_SUCCESS)
12640         {
12641             return(stat);
12642         }
12643
12644         tng_block_init(&block);
12645         block->name = malloc(TNG_MAX_STR_LEN);
12646         if(!block->name)
12647         {
12648             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
12649                     TNG_MAX_STR_LEN, __FILE__, __LINE__);
12650             tng_block_destroy(&block);
12651             return(TNG_CRITICAL);
12652         }
12653         strcpy(block->name, "GENERAL INFO");
12654         tng_block_header_len_calculate(tng_data, block, &len);
12655         tot_len += len;
12656         tng_general_info_block_len_calculate(tng_data, &len);
12657         tot_len += len;
12658         strcpy(block->name, "MOLECULES");
12659         tng_block_header_len_calculate(tng_data, block, &len);
12660         tot_len += len;
12661         tng_molecules_block_len_calculate(tng_data, &len);
12662         tot_len += len;
12663
12664         for(i = 0; i < tng_data->n_data_blocks; i++)
12665         {
12666             strcpy(block->name, tng_data->non_tr_data[i].block_name);
12667             tng_block_header_len_calculate(tng_data, block, &len);
12668             tot_len += len;
12669             tng_data_block_len_calculate(tng_data,
12670                                         (tng_particle_data_t)&tng_data->non_tr_data[i],
12671                                         TNG_FALSE, 1, 1, 1, 0,
12672                                         1, 0, &data_start_pos,
12673                                         &len);
12674             tot_len += len;
12675         }
12676         for(i = 0; i < tng_data->n_particle_data_blocks; i++)
12677         {
12678             strcpy(block->name, tng_data->non_tr_particle_data[i].block_name);
12679             tng_block_header_len_calculate(tng_data, block, &len);
12680             tot_len += len;
12681             tng_data_block_len_calculate(tng_data,
12682                                         &tng_data->non_tr_particle_data[i],
12683                                         TNG_TRUE, 1, 1, 1, 0,
12684                                         tng_data->n_particles, TNG_PARTICLE_DEPENDENT,
12685                                         &data_start_pos,
12686                                         &len);
12687             tot_len += len;
12688         }
12689         tng_block_destroy(&block);
12690
12691         if(tot_len > orig_len)
12692         {
12693             tng_migrate_data_in_file(tng_data, orig_len+1, tot_len - orig_len);
12694         }
12695
12696         tng_data->current_trajectory_frame_set_output_file_pos = -1;
12697     }
12698
12699     /* TODO: If there is already frame set data written to this file (e.g. when
12700      * appending to an already existing file we might need to move frame sets to
12701      * the end of the file. */
12702
12703     if(tng_general_info_block_write(tng_data, hash_mode)
12704        != TNG_SUCCESS)
12705     {
12706         fprintf(stderr, "TNG library: Error writing general info block of file %s. %s: %d\n",
12707                 tng_data->input_file_path, __FILE__, __LINE__);
12708         return(TNG_CRITICAL);
12709     }
12710
12711     if(tng_molecules_block_write(tng_data, hash_mode)
12712         != TNG_SUCCESS)
12713     {
12714         fprintf(stderr, "TNG library: Error writing atom names block of file %s. %s: %d\n",
12715                 tng_data->input_file_path, __FILE__, __LINE__);
12716         return(TNG_CRITICAL);
12717     }
12718
12719     /* FIXME: Currently writing non-trajectory data blocks here.
12720      * Should perhaps be moved. */
12721     tng_block_init(&block);
12722     for(i = 0; i < tng_data->n_data_blocks; i++)
12723     {
12724         block->id = tng_data->non_tr_data[i].block_id;
12725         tng_data_block_write(tng_data, block,
12726                              i, hash_mode);
12727     }
12728
12729     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
12730     {
12731         block->id = tng_data->non_tr_particle_data[i].block_id;
12732         tng_particle_data_block_write(tng_data, block,
12733                                       i, 0, hash_mode);
12734     }
12735
12736     tng_block_destroy(&block);
12737
12738     return(TNG_SUCCESS);
12739 }
12740
12741 tng_function_status DECLSPECDLLEXPORT tng_block_read_next(tng_trajectory_t tng_data,
12742                                         tng_gen_block_t block,
12743                                         const char hash_mode)
12744 {
12745     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12746     TNG_ASSERT(block, "TNG library: block must be initialised and must not be a NULL pointer.");
12747
12748     switch(block->id)
12749     {
12750     case TNG_TRAJECTORY_FRAME_SET:
12751         return(tng_frame_set_block_read(tng_data, block, hash_mode));
12752     case TNG_PARTICLE_MAPPING:
12753         return(tng_trajectory_mapping_block_read(tng_data, block, hash_mode));
12754     case TNG_GENERAL_INFO:
12755         return(tng_general_info_block_read(tng_data, block, hash_mode));
12756     case TNG_MOLECULES:
12757         return(tng_molecules_block_read(tng_data, block, hash_mode));
12758     default:
12759         if(block->id >= TNG_TRAJ_BOX_SHAPE)
12760         {
12761             return(tng_data_block_contents_read(tng_data, block, hash_mode));
12762         }
12763         else
12764         {
12765             /* Skip to the next block */
12766             fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
12767             return(TNG_FAILURE);
12768         }
12769     }
12770 }
12771
12772 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read
12773                 (tng_trajectory_t tng_data,
12774                  const char hash_mode)
12775 {
12776     long file_pos;
12777     tng_gen_block_t block;
12778     tng_function_status stat;
12779
12780     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12781
12782     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12783     {
12784         return(TNG_CRITICAL);
12785     }
12786
12787     file_pos = ftell(tng_data->input_file);
12788
12789     tng_block_init(&block);
12790
12791     if(!tng_data->input_file_len)
12792     {
12793         fseek(tng_data->input_file, 0, SEEK_END);
12794         tng_data->input_file_len = ftell(tng_data->input_file);
12795         fseek(tng_data->input_file, file_pos, SEEK_SET);
12796     }
12797
12798     /* Read block headers first to see what block is found. */
12799     stat = tng_block_header_read(tng_data, block);
12800     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET ||
12801        block->id == -1)
12802     {
12803         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
12804                file_pos, __FILE__, __LINE__);
12805         tng_block_destroy(&block);
12806         return(TNG_CRITICAL);
12807     }
12808
12809     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
12810
12811     if(tng_block_read_next(tng_data, block,
12812                            hash_mode) == TNG_SUCCESS)
12813     {
12814         tng_data->n_trajectory_frame_sets++;
12815         file_pos = ftell(tng_data->input_file);
12816         /* Read all blocks until next frame set block */
12817         stat = tng_block_header_read(tng_data, block);
12818         while(file_pos < tng_data->input_file_len &&
12819               stat != TNG_CRITICAL &&
12820               block->id != TNG_TRAJECTORY_FRAME_SET &&
12821               block->id != -1)
12822         {
12823             stat = tng_block_read_next(tng_data, block,
12824                                        hash_mode);
12825             if(stat != TNG_CRITICAL)
12826             {
12827                 file_pos = ftell(tng_data->input_file);
12828                 if(file_pos < tng_data->input_file_len)
12829                 {
12830                     stat = tng_block_header_read(tng_data, block);
12831                 }
12832             }
12833         }
12834         if(stat == TNG_CRITICAL)
12835         {
12836             fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
12837                    file_pos, __FILE__, __LINE__);
12838             tng_block_destroy(&block);
12839             return(stat);
12840         }
12841
12842         if(block->id == TNG_TRAJECTORY_FRAME_SET)
12843         {
12844             fseek(tng_data->input_file, file_pos, SEEK_SET);
12845         }
12846     }
12847
12848     tng_block_destroy(&block);
12849
12850     return(TNG_SUCCESS);
12851 }
12852
12853
12854 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_current_only_data_from_block_id
12855                 (tng_trajectory_t tng_data,
12856                  const char hash_mode,
12857                  const int64_t block_id)
12858 {
12859     long file_pos;
12860     tng_gen_block_t block;
12861     tng_function_status stat;
12862     int found_flag = 1;
12863
12864     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12865
12866     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12867     {
12868         return(TNG_CRITICAL);
12869     }
12870
12871     file_pos = (long)tng_data->current_trajectory_frame_set_input_file_pos;
12872
12873     if(file_pos < 0)
12874     {
12875         /* No current frame set. This means that the first frame set must be
12876          * read */
12877         found_flag = 0;
12878         file_pos = (long)tng_data->first_trajectory_frame_set_input_file_pos;
12879     }
12880
12881     if(file_pos > 0)
12882     {
12883         fseek(tng_data->input_file,
12884               file_pos,
12885               SEEK_SET);
12886     }
12887     else
12888     {
12889         return(TNG_FAILURE);
12890     }
12891
12892     tng_block_init(&block);
12893
12894     if(!tng_data->input_file_len)
12895     {
12896         fseek(tng_data->input_file, 0, SEEK_END);
12897         tng_data->input_file_len = ftell(tng_data->input_file);
12898         fseek(tng_data->input_file, file_pos, SEEK_SET);
12899     }
12900
12901     /* Read block headers first to see what block is found. */
12902     stat = tng_block_header_read(tng_data, block);
12903     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12904     {
12905         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
12906                file_pos, __FILE__, __LINE__);
12907         tng_block_destroy(&block);
12908         return(TNG_CRITICAL);
12909     }
12910     /* If the current frame set had already been read skip its block contents */
12911     if(found_flag)
12912     {
12913         fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
12914     }
12915     /* Otherwiese read the frame set block */
12916     else
12917     {
12918         stat = tng_block_read_next(tng_data, block,
12919                                    hash_mode);
12920         if(stat != TNG_SUCCESS)
12921         {
12922             fprintf(stderr, "TNG library: Cannot read frame set block. %s: %d\n", __FILE__, __LINE__);
12923             tng_block_destroy(&block);
12924             return(stat);
12925         }
12926     }
12927     file_pos = ftell(tng_data->input_file);
12928
12929     found_flag = 0;
12930
12931     /* Read only blocks of the requested ID
12932         * until next frame set block */
12933     stat = tng_block_header_read(tng_data, block);
12934     while(file_pos < tng_data->input_file_len &&
12935             stat != TNG_CRITICAL &&
12936             block->id != TNG_TRAJECTORY_FRAME_SET &&
12937             block->id != -1)
12938     {
12939         if(block->id == block_id)
12940         {
12941             stat = tng_block_read_next(tng_data, block,
12942                                        hash_mode);
12943             if(stat != TNG_CRITICAL)
12944             {
12945                 file_pos = ftell(tng_data->input_file);
12946                 found_flag = 1;
12947                 if(file_pos < tng_data->input_file_len)
12948                 {
12949                     stat = tng_block_header_read(tng_data, block);
12950                 }
12951             }
12952         }
12953         else
12954         {
12955             file_pos += (long)(block->block_contents_size + block->header_contents_size);
12956             fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
12957             if(file_pos < tng_data->input_file_len)
12958             {
12959                 stat = tng_block_header_read(tng_data, block);
12960             }
12961         }
12962     }
12963     if(stat == TNG_CRITICAL)
12964     {
12965         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
12966                 file_pos, __FILE__, __LINE__);
12967         tng_block_destroy(&block);
12968         return(stat);
12969     }
12970
12971     if(block->id == TNG_TRAJECTORY_FRAME_SET)
12972     {
12973         fseek(tng_data->input_file, file_pos, SEEK_SET);
12974     }
12975
12976     tng_block_destroy(&block);
12977
12978     if(found_flag)
12979     {
12980         return(TNG_SUCCESS);
12981     }
12982     else
12983     {
12984         return(TNG_FAILURE);
12985     }
12986 }
12987
12988 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next
12989                 (tng_trajectory_t tng_data,
12990                  const char hash_mode)
12991 {
12992     long file_pos;
12993
12994     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12995
12996     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12997     {
12998         return(TNG_CRITICAL);
12999     }
13000
13001     file_pos = (long)tng_data->current_trajectory_frame_set.next_frame_set_file_pos;
13002
13003     if(file_pos < 0 && tng_data->current_trajectory_frame_set_input_file_pos <= 0)
13004     {
13005         file_pos = (long)tng_data->first_trajectory_frame_set_input_file_pos;
13006     }
13007
13008     if(file_pos > 0)
13009     {
13010         fseek(tng_data->input_file,
13011               file_pos,
13012               SEEK_SET);
13013     }
13014     else
13015     {
13016         return(TNG_FAILURE);
13017     }
13018
13019     return(tng_frame_set_read(tng_data, hash_mode));
13020 }
13021
13022 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next_only_data_from_block_id
13023                 (tng_trajectory_t tng_data,
13024                  const char hash_mode,
13025                  const int64_t block_id)
13026 {
13027     long file_pos;
13028     tng_gen_block_t block;
13029     tng_function_status stat;
13030
13031     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13032
13033     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
13034     {
13035         return(TNG_CRITICAL);
13036     }
13037
13038     file_pos = (long)tng_data->current_trajectory_frame_set.next_frame_set_file_pos;
13039
13040     if(file_pos < 0 && tng_data->current_trajectory_frame_set_input_file_pos <= 0)
13041     {
13042         file_pos = (long)tng_data->first_trajectory_frame_set_input_file_pos;
13043     }
13044
13045     if(file_pos > 0)
13046     {
13047         fseek(tng_data->input_file,
13048               file_pos,
13049               SEEK_SET);
13050     }
13051     else
13052     {
13053         return(TNG_FAILURE);
13054     }
13055
13056     tng_block_init(&block);
13057
13058     if(!tng_data->input_file_len)
13059     {
13060         fseek(tng_data->input_file, 0, SEEK_END);
13061         tng_data->input_file_len = ftell(tng_data->input_file);
13062         fseek(tng_data->input_file, file_pos, SEEK_SET);
13063     }
13064
13065     /* Read block headers first to see what block is found. */
13066     stat = tng_block_header_read(tng_data, block);
13067     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
13068     {
13069         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
13070                file_pos, __FILE__, __LINE__);
13071         tng_block_destroy(&block);
13072         return(TNG_CRITICAL);
13073     }
13074
13075     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
13076
13077     if(tng_block_read_next(tng_data, block,
13078                            hash_mode) == TNG_SUCCESS)
13079     {
13080         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, hash_mode, block_id);
13081     }
13082
13083     tng_block_destroy(&block);
13084
13085     return(stat);
13086 }
13087
13088 tng_function_status tng_frame_set_write(tng_trajectory_t tng_data,
13089                                         const char hash_mode)
13090 {
13091     int i, j;
13092     tng_gen_block_t block;
13093     tng_trajectory_frame_set_t frame_set;
13094     tng_function_status stat;
13095
13096     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13097
13098     frame_set = &tng_data->current_trajectory_frame_set;
13099
13100     if(frame_set->n_written_frames == frame_set->n_frames)
13101     {
13102         return(TNG_SUCCESS);
13103     }
13104
13105     tng_data->current_trajectory_frame_set_output_file_pos =
13106     ftell(tng_data->output_file);
13107     tng_data->last_trajectory_frame_set_output_file_pos =
13108     tng_data->current_trajectory_frame_set_output_file_pos;
13109
13110     if(tng_data->current_trajectory_frame_set_output_file_pos <= 0)
13111     {
13112         return(TNG_FAILURE);
13113     }
13114
13115     if(tng_data->first_trajectory_frame_set_output_file_pos == -1)
13116     {
13117         tng_data->first_trajectory_frame_set_output_file_pos =
13118         tng_data->current_trajectory_frame_set_output_file_pos;
13119     }
13120
13121     tng_block_init(&block);
13122
13123     if(tng_frame_set_block_write(tng_data, block, hash_mode) != TNG_SUCCESS)
13124     {
13125         tng_block_destroy(&block);
13126         return(TNG_FAILURE);
13127     }
13128
13129     /* Write non-particle data blocks */
13130     for(i = 0; i<frame_set->n_data_blocks; i++)
13131     {
13132         block->id = frame_set->tr_data[i].block_id;
13133         tng_data_block_write(tng_data, block, i, hash_mode);
13134     }
13135     /* Write the mapping blocks and particle data blocks*/
13136     if(frame_set->n_mapping_blocks)
13137     {
13138         for(i = 0; i < frame_set->n_mapping_blocks; i++)
13139         {
13140             block->id = TNG_PARTICLE_MAPPING;
13141             if(frame_set->mappings[i].n_particles > 0)
13142             {
13143                 tng_trajectory_mapping_block_write(tng_data, block, i, hash_mode);
13144                 for(j = 0; j<frame_set->n_particle_data_blocks; j++)
13145                 {
13146                     block->id = frame_set->tr_particle_data[j].block_id;
13147                     tng_particle_data_block_write(tng_data, block,
13148                                                   j, &frame_set->mappings[i],
13149                                                   hash_mode);
13150                 }
13151             }
13152         }
13153     }
13154     else
13155     {
13156         for(i = 0; i<frame_set->n_particle_data_blocks; i++)
13157         {
13158             block->id = frame_set->tr_particle_data[i].block_id;
13159             tng_particle_data_block_write(tng_data, block,
13160                                           i, 0, hash_mode);
13161         }
13162     }
13163
13164
13165     /* Update pointers in the general info block */
13166     stat = tng_header_pointers_update(tng_data, hash_mode);
13167
13168     if(stat == TNG_SUCCESS)
13169     {
13170         stat = tng_frame_set_pointers_update(tng_data, hash_mode);
13171     }
13172
13173     tng_block_destroy(&block);
13174
13175     frame_set->n_unwritten_frames = 0;
13176
13177     fflush(tng_data->output_file);
13178
13179     return(stat);
13180 }
13181
13182 tng_function_status DECLSPECDLLEXPORT tng_frame_set_premature_write
13183                 (tng_trajectory_t tng_data,
13184                  const char hash_mode)
13185 {
13186     tng_trajectory_frame_set_t frame_set;
13187
13188     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13189
13190     frame_set = &tng_data->current_trajectory_frame_set;
13191
13192     if(frame_set->n_unwritten_frames == 0)
13193     {
13194         return(TNG_SUCCESS);
13195     }
13196     frame_set->n_frames = frame_set->n_unwritten_frames;
13197
13198     return(tng_frame_set_write(tng_data, hash_mode));
13199 }
13200
13201 tng_function_status DECLSPECDLLEXPORT tng_frame_set_new
13202                 (tng_trajectory_t tng_data,
13203                  const int64_t first_frame,
13204                  const int64_t n_frames)
13205 {
13206     tng_gen_block_t block;
13207     tng_trajectory_frame_set_t frame_set;
13208     FILE *temp = tng_data->input_file;
13209     int64_t curr_pos;
13210
13211     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13212     TNG_ASSERT(first_frame >= 0, "TNG library: first_frame must be >= 0.");
13213     TNG_ASSERT(n_frames >= 0, "TNG library: n_frames must be >= 0.");
13214
13215     frame_set = &tng_data->current_trajectory_frame_set;
13216
13217     curr_pos = ftell(tng_data->output_file);
13218
13219     if(curr_pos <= 10)
13220     {
13221         tng_file_headers_write(tng_data, TNG_USE_HASH);
13222     }
13223
13224     /* Set pointer to previous frame set to the one that was loaded
13225      * before.
13226      * FIXME: This is a bit risky. If they are not added in order
13227      * it will be wrong. */
13228     if(tng_data->n_trajectory_frame_sets)
13229     {
13230         frame_set->prev_frame_set_file_pos =
13231         tng_data->current_trajectory_frame_set_output_file_pos;
13232     }
13233
13234     tng_data->current_trajectory_frame_set_output_file_pos =
13235     ftell(tng_data->output_file);
13236
13237     tng_data->n_trajectory_frame_sets++;
13238
13239     /* Set the medium range pointers */
13240     if(tng_data->n_trajectory_frame_sets == tng_data->medium_stride_length + 1)
13241     {
13242         frame_set->medium_stride_prev_frame_set_file_pos =
13243         tng_data->first_trajectory_frame_set_output_file_pos;
13244     }
13245     else if(tng_data->n_trajectory_frame_sets > tng_data->medium_stride_length + 1)
13246     {
13247         /* FIXME: Currently only working if the previous frame set has its
13248          * medium stride pointer already set. This might need some fixing. */
13249         if(frame_set->medium_stride_prev_frame_set_file_pos != -1 &&
13250            frame_set->medium_stride_prev_frame_set_file_pos != 0)
13251         {
13252             tng_block_init(&block);
13253             tng_data->input_file = tng_data->output_file;
13254
13255             curr_pos = ftell(tng_data->output_file);
13256             fseek(tng_data->output_file,
13257                   (long)frame_set->medium_stride_prev_frame_set_file_pos,
13258                   SEEK_SET);
13259
13260             if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
13261             {
13262                 fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
13263                     __FILE__, __LINE__);
13264                 tng_data->input_file = temp;
13265                 tng_block_destroy(&block);
13266                 return(TNG_CRITICAL);
13267             }
13268
13269             /* Read the next frame set from the previous frame set and one
13270              * medium stride step back */
13271             fseek(tng_data->output_file, (long)block->block_contents_size - (6 *
13272             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
13273             if(fread(&frame_set->medium_stride_prev_frame_set_file_pos,
13274                sizeof(frame_set->medium_stride_prev_frame_set_file_pos),
13275                1, tng_data->output_file) == 0)
13276             {
13277                 fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
13278                 tng_data->input_file = temp;
13279                 tng_block_destroy(&block);
13280                 return(TNG_CRITICAL);
13281             }
13282
13283             if(tng_data->input_endianness_swap_func_64)
13284             {
13285                 if(tng_data->input_endianness_swap_func_64(tng_data,
13286                    &frame_set->medium_stride_prev_frame_set_file_pos)
13287                     != TNG_SUCCESS)
13288                 {
13289                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13290                             __FILE__, __LINE__);
13291                 }
13292             }
13293
13294             tng_block_destroy(&block);
13295
13296             /* Set the long range pointers */
13297             if(tng_data->n_trajectory_frame_sets == tng_data->long_stride_length + 1)
13298             {
13299                 frame_set->long_stride_prev_frame_set_file_pos =
13300                 tng_data->first_trajectory_frame_set_output_file_pos;
13301             }
13302             else if(tng_data->n_trajectory_frame_sets > tng_data->medium_stride_length + 1)
13303             {
13304                 /* FIXME: Currently only working if the previous frame set has its
13305                 * long stride pointer already set. This might need some fixing. */
13306                 if(frame_set->long_stride_prev_frame_set_file_pos != -1 &&
13307                 frame_set->long_stride_prev_frame_set_file_pos != 0)
13308                 {
13309                     tng_block_init(&block);
13310                     tng_data->input_file = tng_data->output_file;
13311
13312                     fseek(tng_data->output_file,
13313                           (long)frame_set->long_stride_prev_frame_set_file_pos,
13314                           SEEK_SET);
13315
13316                     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
13317                     {
13318                         fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
13319                             __FILE__, __LINE__);
13320                         tng_data->input_file = temp;
13321                         tng_block_destroy(&block);
13322                         return(TNG_CRITICAL);
13323                     }
13324
13325                     /* Read the next frame set from the previous frame set and one
13326                     * long stride step back */
13327                     fseek(tng_data->output_file, (long)block->block_contents_size - (6 *
13328                           sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
13329
13330                     tng_block_destroy(&block);
13331
13332                     if(fread(&frame_set->long_stride_prev_frame_set_file_pos,
13333                     sizeof(frame_set->long_stride_prev_frame_set_file_pos),
13334                     1, tng_data->output_file) == 0)
13335                     {
13336                         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
13337                         tng_data->input_file = temp;
13338                         return(TNG_CRITICAL);
13339                     }
13340
13341                     if(tng_data->input_endianness_swap_func_64)
13342                     {
13343                         if(tng_data->input_endianness_swap_func_64(tng_data,
13344                            &frame_set->long_stride_prev_frame_set_file_pos)
13345                             != TNG_SUCCESS)
13346                         {
13347                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13348                                     __FILE__, __LINE__);
13349                         }
13350                     }
13351
13352                 }
13353             }
13354
13355             tng_data->input_file = temp;
13356             fseek(tng_data->output_file, (long)curr_pos, SEEK_SET);
13357         }
13358     }
13359
13360     frame_set->first_frame = first_frame;
13361     frame_set->n_frames = n_frames;
13362     frame_set->n_written_frames = 0;
13363     frame_set->n_unwritten_frames = 0;
13364     frame_set->first_frame_time = -1;
13365
13366     if(tng_data->first_trajectory_frame_set_output_file_pos == -1 ||
13367        tng_data->first_trajectory_frame_set_output_file_pos == 0)
13368     {
13369         tng_data->first_trajectory_frame_set_output_file_pos =
13370         tng_data->current_trajectory_frame_set_output_file_pos;
13371     }
13372     /* FIXME: Should check the frame number instead of the file_pos,
13373      * in case frame sets are not in order */
13374     if(tng_data->last_trajectory_frame_set_output_file_pos == -1 ||
13375        tng_data->last_trajectory_frame_set_output_file_pos == 0 ||
13376        tng_data->last_trajectory_frame_set_output_file_pos <
13377        tng_data->current_trajectory_frame_set_output_file_pos)
13378     {
13379         tng_data->last_trajectory_frame_set_output_file_pos =
13380         tng_data->current_trajectory_frame_set_output_file_pos;
13381     }
13382
13383     return(TNG_SUCCESS);
13384 }
13385
13386 tng_function_status DECLSPECDLLEXPORT tng_frame_set_with_time_new
13387                 (tng_trajectory_t tng_data,
13388                  const int64_t first_frame,
13389                  const int64_t n_frames,
13390                  const double first_frame_time)
13391 {
13392     tng_function_status stat;
13393
13394     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13395     TNG_ASSERT(first_frame >= 0, "TNG library: first_frame must be >= 0.");
13396     TNG_ASSERT(n_frames >= 0, "TNG library: n_frames must be >= 0.");
13397     TNG_ASSERT(first_frame_time >= 0, "TNG library: first_frame_time must be >= 0.");
13398
13399
13400     stat = tng_frame_set_new(tng_data, first_frame, n_frames);
13401     if(stat != TNG_SUCCESS)
13402     {
13403         return(stat);
13404     }
13405     stat = tng_frame_set_first_frame_time_set(tng_data, first_frame_time);
13406
13407     return(stat);
13408 }
13409
13410 tng_function_status DECLSPECDLLEXPORT tng_frame_set_first_frame_time_set
13411                 (tng_trajectory_t tng_data,
13412                  const double first_frame_time)
13413 {
13414     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13415     TNG_ASSERT(first_frame_time >= 0, "TNG library: first_frame_time must be >= 0.");
13416
13417     tng_data->current_trajectory_frame_set.first_frame_time = first_frame_time;
13418
13419     return(TNG_SUCCESS);
13420 }
13421
13422 tng_function_status DECLSPECDLLEXPORT tng_first_frame_nr_of_next_frame_set_get
13423                 (const tng_trajectory_t tng_data,
13424                  int64_t *frame)
13425 {
13426     long file_pos, next_frame_set_file_pos;
13427     tng_gen_block_t block;
13428     tng_function_status stat;
13429
13430     tng_trajectory_frame_set_t frame_set;
13431
13432     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13433     TNG_ASSERT(tng_data->input_file, "TNG library: An input file must be open to find the next frame set");
13434     TNG_ASSERT(frame, "TNG library: frame must not be a NULL pointer");
13435
13436     file_pos = ftell(tng_data->input_file);
13437
13438     if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
13439     {
13440         next_frame_set_file_pos = (long)tng_data->first_trajectory_frame_set_input_file_pos;
13441     }
13442     else
13443     {
13444         frame_set = &tng_data->current_trajectory_frame_set;
13445         next_frame_set_file_pos = (long)frame_set->next_frame_set_file_pos;
13446     }
13447
13448     if(next_frame_set_file_pos <= 0)
13449     {
13450         return(TNG_FAILURE);
13451     }
13452
13453     fseek(tng_data->input_file, (long)next_frame_set_file_pos, SEEK_SET);
13454     /* Read block headers first to see that a frame set block is found. */
13455     tng_block_init(&block);
13456     stat = tng_block_header_read(tng_data, block);
13457     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
13458     {
13459         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
13460                file_pos, __FILE__, __LINE__);
13461         return(TNG_CRITICAL);
13462     }
13463 /*    if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
13464     {
13465         tng_block_read_next(tng_data, block, TNG_USE_HASH);
13466     }*/
13467     tng_block_destroy(&block);
13468
13469     if(fread(frame, sizeof(int64_t), 1, tng_data->input_file) == 0)
13470     {
13471         fprintf(stderr, "TNG library: Cannot read first frame of next frame set. %s: %d\n",
13472                __FILE__, __LINE__);
13473         return(TNG_CRITICAL);
13474     }
13475     fseek(tng_data->input_file, file_pos, SEEK_SET);
13476
13477     return(TNG_SUCCESS);
13478 }
13479
13480 tng_function_status DECLSPECDLLEXPORT tng_data_block_add
13481                 (tng_trajectory_t tng_data,
13482                  const int64_t id,
13483                  const char *block_name,
13484                  const char datatype,
13485                  const char block_type_flag,
13486                  int64_t n_frames,
13487                  const int64_t n_values_per_frame,
13488                  int64_t stride_length,
13489                  const int64_t codec_id,
13490                  void *new_data)
13491 {
13492     int i, j, size, len;
13493     tng_trajectory_frame_set_t frame_set;
13494     tng_non_particle_data_t data;
13495     char **first_dim_values;
13496     char *new_data_c=new_data;
13497     int64_t n_frames_div;
13498
13499     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13500     TNG_ASSERT(block_name, "TNG library: block_name must not be a NULL pointer.");
13501     TNG_ASSERT(n_values_per_frame > 0, "TNG library: n_values_per_frame must be a positive integer.");
13502
13503     frame_set = &tng_data->current_trajectory_frame_set;
13504
13505     if(stride_length <= 0)
13506     {
13507         stride_length = 1;
13508     }
13509
13510     /* If the block does not exist, create it */
13511     if(tng_data_find(tng_data, id, &data) != TNG_SUCCESS)
13512     {
13513         if(tng_data_block_create(tng_data, block_type_flag) !=
13514             TNG_SUCCESS)
13515         {
13516             fprintf(stderr, "TNG library: Cannot create data block. %s: %d\n",
13517                    __FILE__, __LINE__);
13518             return(TNG_CRITICAL);
13519         }
13520         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
13521         {
13522             data = &frame_set->tr_data[frame_set->n_data_blocks - 1];
13523         }
13524         else
13525         {
13526             data = &tng_data->non_tr_data[tng_data->n_data_blocks - 1];
13527         }
13528         data->block_id = id;
13529
13530         data->block_name = malloc(strlen(block_name) + 1);
13531         if(!data->block_name)
13532         {
13533             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
13534                    (int)strlen(block_name)+1, __FILE__, __LINE__);
13535             return(TNG_CRITICAL);
13536         }
13537         strncpy(data->block_name, block_name, strlen(block_name) + 1);
13538
13539         data->values = 0;
13540         /* FIXME: Memory leak from strings. */
13541         data->strings = 0;
13542         data->last_retrieved_frame = -1;
13543     }
13544
13545     data->datatype = datatype;
13546     data->stride_length = tng_max_i64(stride_length, 1);
13547     data->n_values_per_frame = n_values_per_frame;
13548     data->n_frames = n_frames;
13549     data->codec_id = codec_id;
13550     data->compression_multiplier = 1.0;
13551     /* FIXME: This can cause problems. */
13552     data->first_frame_with_data = frame_set->first_frame;
13553
13554     switch(datatype)
13555     {
13556     case TNG_FLOAT_DATA:
13557         size = sizeof(float);
13558         break;
13559     case TNG_INT_DATA:
13560         size = sizeof(int64_t);
13561         break;
13562     case TNG_DOUBLE_DATA:
13563     default:
13564         size = sizeof(double);
13565         break;
13566     }
13567
13568     if(new_data_c)
13569     {
13570         /* Allocate memory */
13571         if(tng_allocate_data_mem(tng_data, data, n_frames, stride_length,
13572                                  n_values_per_frame) !=
13573         TNG_SUCCESS)
13574         {
13575             fprintf(stderr, "TNG library: Cannot allocate data memory. %s: %d\n",
13576                 __FILE__, __LINE__);
13577             return(TNG_CRITICAL);
13578         }
13579
13580         if(n_frames > frame_set->n_unwritten_frames)
13581         {
13582             frame_set->n_unwritten_frames = n_frames;
13583         }
13584
13585         n_frames_div = (n_frames % stride_length) ?
13586                      n_frames / stride_length + 1:
13587                      n_frames / stride_length;
13588
13589         if(datatype == TNG_CHAR_DATA)
13590         {
13591             for(i = 0; i < n_frames_div; i++)
13592             {
13593                 first_dim_values = data->strings[i];
13594                 for(j = 0; j < n_values_per_frame; j++)
13595                 {
13596                     len = tng_min_i((int)strlen(new_data_c) + 1,
13597                                 TNG_MAX_STR_LEN);
13598                     if(first_dim_values[j])
13599                     {
13600                         free(first_dim_values[j]);
13601                     }
13602                     first_dim_values[j] = malloc(len);
13603                     if(!first_dim_values[j])
13604                     {
13605                         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
13606                             len, __FILE__, __LINE__);
13607                         return(TNG_CRITICAL);
13608                     }
13609                     strncpy(first_dim_values[j],
13610                             new_data_c, len);
13611                     new_data_c += len;
13612                 }
13613             }
13614         }
13615         else
13616         {
13617             memcpy(data->values, new_data, size * n_frames_div *
13618                    n_values_per_frame);
13619         }
13620     }
13621
13622     return(TNG_SUCCESS);
13623 }
13624
13625 tng_function_status DECLSPECDLLEXPORT tng_particle_data_block_add
13626                 (tng_trajectory_t tng_data,
13627                  const int64_t id,
13628                  const char *block_name,
13629                  const char datatype,
13630                  const char block_type_flag,
13631                  int64_t n_frames,
13632                  const int64_t n_values_per_frame,
13633                  int64_t stride_length,
13634                  const int64_t num_first_particle,
13635                  const int64_t n_particles,
13636                  const int64_t codec_id,
13637                  void *new_data)
13638 {
13639     int i, size, len;
13640     int64_t j, k;
13641     int64_t tot_n_particles, n_frames_div;
13642     char ***first_dim_values, **second_dim_values;
13643     tng_trajectory_frame_set_t frame_set;
13644     tng_particle_data_t data;
13645     char *new_data_c=new_data;
13646
13647     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13648     TNG_ASSERT(block_name, "TNG library: block_name mustnot be a NULL pointer.");
13649     TNG_ASSERT(n_values_per_frame > 0, "TNG library: n_values_per_frame must be a positive integer.");
13650     TNG_ASSERT(num_first_particle >= 0, "TNG library: num_first_particle must be >= 0.");
13651     TNG_ASSERT(n_particles >= 0, "TNG library: n_particles must be >= 0.");
13652
13653
13654     frame_set = &tng_data->current_trajectory_frame_set;
13655
13656     if(stride_length <= 0)
13657     {
13658         stride_length = 1;
13659     }
13660
13661     /* If the block does not exist, create it */
13662     if(tng_particle_data_find(tng_data, id, &data) != TNG_SUCCESS)
13663     {
13664         if(tng_particle_data_block_create(tng_data, block_type_flag) !=
13665             TNG_SUCCESS)
13666         {
13667             fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n",
13668                    __FILE__, __LINE__);
13669             return(TNG_CRITICAL);
13670         }
13671         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
13672         {
13673             data = &frame_set->tr_particle_data[frame_set->
13674                                                 n_particle_data_blocks - 1];
13675         }
13676         else
13677         {
13678             data = &tng_data->non_tr_particle_data[tng_data->
13679                                                    n_particle_data_blocks - 1];
13680         }
13681         data->block_id = id;
13682
13683         data->block_name = malloc(strlen(block_name) + 1);
13684         if(!data->block_name)
13685         {
13686             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
13687                    (int)strlen(block_name)+1, __FILE__, __LINE__);
13688             return(TNG_CRITICAL);
13689         }
13690         strncpy(data->block_name, block_name, strlen(block_name) + 1);
13691
13692         data->datatype = datatype;
13693
13694         data->values = 0;
13695         /* FIXME: Memory leak from strings. */
13696         data->strings = 0;
13697         data->last_retrieved_frame = -1;
13698     }
13699
13700     data->stride_length = tng_max_i64(stride_length, 1);
13701     data->n_values_per_frame = n_values_per_frame;
13702     data->n_frames = n_frames;
13703     data->codec_id = codec_id;
13704     data->compression_multiplier = 1.0;
13705     /* FIXME: This can cause problems. */
13706     data->first_frame_with_data = frame_set->first_frame;
13707
13708     if(block_type_flag == TNG_TRAJECTORY_BLOCK && tng_data->var_num_atoms_flag)
13709     {
13710         tot_n_particles = frame_set->n_particles;
13711     }
13712     else
13713     {
13714         tot_n_particles = tng_data->n_particles;
13715     }
13716
13717     /* If data values are supplied add that data to the data block. */
13718     if(new_data_c)
13719     {
13720         /* Allocate memory */
13721         if(tng_allocate_particle_data_mem(tng_data, data, n_frames,
13722                                           stride_length, tot_n_particles,
13723                                           n_values_per_frame) !=
13724         TNG_SUCCESS)
13725         {
13726             fprintf(stderr, "TNG library: Cannot allocate particle data memory. %s: %d\n",
13727                 __FILE__, __LINE__);
13728             return(TNG_CRITICAL);
13729         }
13730
13731         if(n_frames > frame_set->n_unwritten_frames)
13732         {
13733             frame_set->n_unwritten_frames = n_frames;
13734         }
13735
13736         n_frames_div = (n_frames % stride_length) ?
13737                      n_frames / stride_length + 1:
13738                      n_frames / stride_length;
13739
13740         if(datatype == TNG_CHAR_DATA)
13741         {
13742             for(i = 0; i < n_frames_div; i++)
13743             {
13744                 first_dim_values = data->strings[i];
13745                 for(j = num_first_particle; j < num_first_particle + n_particles;
13746                     j++)
13747                 {
13748                     second_dim_values = first_dim_values[j];
13749                     for(k = 0; k < n_values_per_frame; k++)
13750                     {
13751                         len = tng_min_i((int)strlen(new_data_c) + 1,
13752                                 TNG_MAX_STR_LEN);
13753                         if(second_dim_values[k])
13754                         {
13755                             free(second_dim_values[k]);
13756                         }
13757                         second_dim_values[k] = malloc(len);
13758                         if(!second_dim_values[k])
13759                         {
13760                             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
13761                                 len, __FILE__, __LINE__);
13762                             return(TNG_CRITICAL);
13763                         }
13764                         strncpy(second_dim_values[k],
13765                                 new_data_c, len);
13766                         new_data_c += len;
13767                     }
13768                 }
13769             }
13770         }
13771         else
13772         {
13773             switch(datatype)
13774             {
13775             case TNG_INT_DATA:
13776                 size = sizeof(int64_t);
13777                 break;
13778             case TNG_FLOAT_DATA:
13779                 size = sizeof(float);
13780                 break;
13781             case TNG_DOUBLE_DATA:
13782             default:
13783                 size = sizeof(double);
13784             }
13785
13786             memcpy(data->values, new_data, size * n_frames_div *
13787                    n_particles * n_values_per_frame);
13788         }
13789     }
13790
13791     return(TNG_SUCCESS);
13792 }
13793
13794 tng_function_status DECLSPECDLLEXPORT tng_data_block_name_get
13795                 (tng_trajectory_t tng_data,
13796                  int64_t block_id,
13797                  char *name,
13798                  int max_len)
13799 {
13800     int64_t i;
13801     tng_trajectory_frame_set_t frame_set;
13802     tng_function_status stat;
13803     tng_particle_data_t p_data;
13804     tng_non_particle_data_t np_data;
13805     int block_type = -1;
13806
13807     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13808     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
13809
13810     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
13811     {
13812         p_data = &tng_data->non_tr_particle_data[i];
13813         if(p_data->block_id == block_id)
13814         {
13815             strncpy(name, p_data->block_name, max_len);
13816             name[max_len - 1] = '\0';
13817             return(TNG_SUCCESS);
13818         }
13819     }
13820     for(i = 0; i < tng_data->n_data_blocks; i++)
13821     {
13822         np_data = &tng_data->non_tr_data[i];
13823         if(np_data->block_id == block_id)
13824         {
13825             strncpy(name, np_data->block_name, max_len);
13826             name[max_len - 1] = '\0';
13827             return(TNG_SUCCESS);
13828         }
13829     }
13830
13831     frame_set = &tng_data->current_trajectory_frame_set;
13832
13833     stat = tng_particle_data_find(tng_data, block_id, &p_data);
13834     if(stat == TNG_SUCCESS)
13835     {
13836         block_type = TNG_PARTICLE_BLOCK_DATA;
13837     }
13838     else
13839     {
13840         stat = tng_data_find(tng_data, block_id, &np_data);
13841         if(stat == TNG_SUCCESS)
13842         {
13843             block_type = TNG_NON_PARTICLE_BLOCK_DATA;
13844         }
13845         else
13846         {
13847             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
13848             if(stat != TNG_SUCCESS)
13849             {
13850                 return(stat);
13851             }
13852             stat = tng_particle_data_find(tng_data, block_id, &p_data);
13853             if(stat == TNG_SUCCESS)
13854             {
13855                 block_type = TNG_PARTICLE_BLOCK_DATA;
13856             }
13857             else
13858             {
13859                 stat = tng_data_find(tng_data, block_id, &np_data);
13860                 if(stat == TNG_SUCCESS)
13861                 {
13862                     block_type = TNG_NON_PARTICLE_BLOCK_DATA;
13863                 }
13864             }
13865         }
13866     }
13867     if(block_type == TNG_PARTICLE_BLOCK_DATA)
13868     {
13869         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
13870         {
13871             p_data = &frame_set->tr_particle_data[i];
13872             if(p_data->block_id == block_id)
13873             {
13874                 strncpy(name, p_data->block_name, max_len);
13875                 name[max_len - 1] = '\0';
13876                 return(TNG_SUCCESS);
13877             }
13878         }
13879     }
13880     else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
13881     {
13882         for(i = 0; i < frame_set->n_data_blocks; i++)
13883         {
13884             np_data = &frame_set->tr_data[i];
13885             if(np_data->block_id == block_id)
13886             {
13887                 strncpy(name, np_data->block_name, max_len);
13888                 name[max_len - 1] = '\0';
13889                 return(TNG_SUCCESS);
13890             }
13891         }
13892     }
13893
13894     return(TNG_FAILURE);
13895 }
13896
13897 tng_function_status DECLSPECDLLEXPORT tng_data_block_dependency_get
13898                 (const tng_trajectory_t tng_data,
13899                  int64_t block_id,
13900                  int *block_dependency)
13901 {
13902     int64_t i;
13903     tng_function_status stat;
13904     tng_particle_data_t p_data;
13905     tng_non_particle_data_t np_data;
13906
13907     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13908     TNG_ASSERT(block_dependency, "TNG library: block_dependency must not be a NULL pointer.");
13909
13910     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
13911     {
13912         p_data = &tng_data->non_tr_particle_data[i];
13913         if(p_data->block_id == block_id)
13914         {
13915             *block_dependency = TNG_PARTICLE_DEPENDENT;
13916             return(TNG_SUCCESS);
13917         }
13918     }
13919     for(i = 0; i < tng_data->n_data_blocks; i++)
13920     {
13921         np_data = &tng_data->non_tr_data[i];
13922         if(np_data->block_id == block_id)
13923         {
13924             *block_dependency = 0;
13925             return(TNG_SUCCESS);
13926         }
13927     }
13928
13929     stat = tng_particle_data_find(tng_data, block_id, &p_data);
13930     if(stat == TNG_SUCCESS)
13931     {
13932         *block_dependency = TNG_PARTICLE_DEPENDENT + TNG_FRAME_DEPENDENT;
13933         return(TNG_SUCCESS);
13934     }
13935     else
13936     {
13937         stat = tng_data_find(tng_data, block_id, &np_data);
13938         if(stat == TNG_SUCCESS)
13939         {
13940             *block_dependency = TNG_FRAME_DEPENDENT;
13941             return(TNG_SUCCESS);
13942         }
13943         else
13944         {
13945             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
13946             if(stat != TNG_SUCCESS)
13947             {
13948                 return(stat);
13949             }
13950             stat = tng_particle_data_find(tng_data, block_id, &p_data);
13951             if(stat == TNG_SUCCESS)
13952             {
13953                 *block_dependency = TNG_PARTICLE_DEPENDENT + TNG_FRAME_DEPENDENT;
13954                 return(TNG_SUCCESS);
13955             }
13956             else
13957             {
13958                 stat = tng_data_find(tng_data, block_id, &np_data);
13959                 if(stat == TNG_SUCCESS)
13960                 {
13961                     *block_dependency = TNG_FRAME_DEPENDENT;
13962                     return(TNG_SUCCESS);
13963                 }
13964             }
13965         }
13966     }
13967
13968     return(TNG_FAILURE);
13969 }
13970
13971 tng_function_status DECLSPECDLLEXPORT tng_data_block_num_values_per_frame_get
13972                 (const tng_trajectory_t tng_data,
13973                  int64_t block_id,
13974                  int64_t *n_values_per_frame)
13975 {
13976     int64_t i;
13977     tng_function_status stat;
13978     tng_particle_data_t p_data;
13979     tng_non_particle_data_t np_data;
13980
13981     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13982     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
13983
13984     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
13985     {
13986         p_data = &tng_data->non_tr_particle_data[i];
13987         if(p_data->block_id == block_id)
13988         {
13989             *n_values_per_frame = p_data->n_values_per_frame;
13990             return(TNG_SUCCESS);
13991         }
13992     }
13993     for(i = 0; i < tng_data->n_data_blocks; i++)
13994     {
13995         np_data = &tng_data->non_tr_data[i];
13996         if(np_data->block_id == block_id)
13997         {
13998             *n_values_per_frame = np_data->n_values_per_frame;
13999             return(TNG_SUCCESS);
14000         }
14001     }
14002
14003     stat = tng_particle_data_find(tng_data, block_id, &p_data);
14004     if(stat == TNG_SUCCESS)
14005     {
14006         *n_values_per_frame = p_data->n_values_per_frame;
14007         return(TNG_SUCCESS);
14008     }
14009     else
14010     {
14011         stat = tng_data_find(tng_data, block_id, &np_data);
14012         if(stat == TNG_SUCCESS)
14013         {
14014             *n_values_per_frame = np_data->n_values_per_frame;
14015             return(TNG_SUCCESS);
14016         }
14017         else
14018         {
14019             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
14020             if(stat != TNG_SUCCESS)
14021             {
14022                 return(stat);
14023             }
14024             stat = tng_particle_data_find(tng_data, block_id, &p_data);
14025             if(stat == TNG_SUCCESS)
14026             {
14027                 *n_values_per_frame = p_data->n_values_per_frame;
14028                 return(TNG_SUCCESS);
14029             }
14030             else
14031             {
14032                 stat = tng_data_find(tng_data, block_id, &np_data);
14033                 if(stat == TNG_SUCCESS)
14034                 {
14035                     *n_values_per_frame = np_data->n_values_per_frame;
14036                     return(TNG_SUCCESS);
14037                 }
14038             }
14039         }
14040     }
14041
14042     return(TNG_FAILURE);
14043 }
14044
14045 tng_function_status DECLSPECDLLEXPORT tng_frame_data_write
14046                 (tng_trajectory_t tng_data,
14047                  const int64_t frame_nr,
14048                  const int64_t block_id,
14049                  const void *values,
14050                  const char hash_mode)
14051 {
14052     int64_t header_pos, file_pos;
14053     int64_t output_file_len, n_values_per_frame, size, contents_size;
14054     int64_t header_size, temp_first, temp_last;
14055     int64_t i, last_frame;
14056     long temp_current;
14057     tng_gen_block_t block;
14058     tng_trajectory_frame_set_t frame_set;
14059     FILE *temp = tng_data->input_file;
14060     struct tng_non_particle_data data;
14061     tng_function_status stat;
14062     char dependency, sparse_data, datatype;
14063     void *copy;
14064
14065     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14066     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
14067     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer.");
14068
14069     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
14070     {
14071         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
14072                __FILE__, __LINE__);
14073         return(TNG_CRITICAL);
14074     }
14075
14076     temp_first = tng_data->first_trajectory_frame_set_input_file_pos;
14077     temp_last = tng_data->last_trajectory_frame_set_input_file_pos;
14078     temp_current = tng_data->current_trajectory_frame_set_input_file_pos;
14079     tng_data->first_trajectory_frame_set_input_file_pos =
14080     tng_data->first_trajectory_frame_set_output_file_pos;
14081     tng_data->last_trajectory_frame_set_input_file_pos =
14082     tng_data->last_trajectory_frame_set_output_file_pos;
14083     tng_data->current_trajectory_frame_set_input_file_pos =
14084     tng_data->current_trajectory_frame_set_output_file_pos;
14085
14086     tng_data->input_file = tng_data->output_file;
14087
14088     stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
14089
14090     frame_set = &tng_data->current_trajectory_frame_set;
14091
14092     if(stat != TNG_SUCCESS)
14093     {
14094         last_frame = frame_set->first_frame +
14095                      frame_set->n_frames - 1;
14096         /* If the wanted frame would be in the frame set after the last
14097             * frame set create a new frame set. */
14098         if(stat == TNG_FAILURE &&
14099             last_frame < frame_nr)
14100 /*           (last_frame < frame_nr &&
14101             tng_data->current_trajectory_frame_set.first_frame +
14102             tng_data->frame_set_n_frames >= frame_nr))*/
14103         {
14104             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
14105             {
14106                 last_frame = frame_nr - 1;
14107             }
14108             tng_frame_set_new(tng_data,
14109                               last_frame+1,
14110                               tng_data->frame_set_n_frames);
14111             file_pos = ftell(tng_data->output_file);
14112             fseek(tng_data->output_file, 0, SEEK_END);
14113             output_file_len = ftell(tng_data->output_file);
14114             fseek(tng_data->output_file, (long)file_pos, SEEK_SET);
14115
14116             /* Read mapping blocks from the last frame set */
14117             tng_block_init(&block);
14118
14119             stat = tng_block_header_read(tng_data, block);
14120             while(file_pos < output_file_len &&
14121                   stat != TNG_CRITICAL &&
14122                   block->id != TNG_TRAJECTORY_FRAME_SET &&
14123                   block->id != -1)
14124             {
14125                 if(block->id == TNG_PARTICLE_MAPPING)
14126                 {
14127                     tng_trajectory_mapping_block_read(tng_data, block,
14128                                                       hash_mode);
14129                 }
14130                 else
14131                 {
14132                     fseek(tng_data->output_file, (long)block->block_contents_size,
14133                         SEEK_CUR);
14134                 }
14135                 file_pos = ftell(tng_data->output_file);
14136                 if(file_pos < output_file_len)
14137                 {
14138                     stat = tng_block_header_read(tng_data, block);
14139                 }
14140             }
14141
14142             tng_block_destroy(&block);
14143             /* Write the frame set to disk */
14144             if(tng_frame_set_write(tng_data, hash_mode) != TNG_SUCCESS)
14145             {
14146                 fprintf(stderr, "TNG library: Error writing frame set. %s: %d\n", __FILE__, __LINE__);
14147                 return(TNG_CRITICAL);
14148             }
14149         }
14150         else
14151         {
14152             tng_data->input_file = temp;
14153             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14154             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14155             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14156             return(stat);
14157         }
14158     }
14159
14160     tng_block_init(&block);
14161
14162     file_pos = tng_data->current_trajectory_frame_set_output_file_pos;
14163
14164     fseek(tng_data->output_file, 0, SEEK_END);
14165     output_file_len = ftell(tng_data->output_file);
14166     fseek(tng_data->output_file, (long)file_pos, SEEK_SET);
14167
14168     /* Read past the frame set block first */
14169     stat = tng_block_header_read(tng_data, block);
14170     if(stat == TNG_CRITICAL)
14171     {
14172         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14173                file_pos, __FILE__, __LINE__);
14174         tng_block_destroy(&block);
14175         tng_data->input_file = temp;
14176
14177         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14178         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14179         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14180         return(stat);
14181     }
14182     fseek(tng_data->output_file, (long)block->block_contents_size,
14183             SEEK_CUR);
14184
14185     /* Read all block headers until next frame set block or
14186      * until the wanted block id is found */
14187     stat = tng_block_header_read(tng_data, block);
14188     while(file_pos < output_file_len &&
14189             stat != TNG_CRITICAL &&
14190             block->id != block_id &&
14191             block->id != TNG_TRAJECTORY_FRAME_SET &&
14192             block->id != -1)
14193     {
14194         fseek(tng_data->output_file, (long)block->block_contents_size, SEEK_CUR);
14195         file_pos = ftell(tng_data->output_file);
14196         if(file_pos < output_file_len)
14197         {
14198             stat = tng_block_header_read(tng_data, block);
14199         }
14200     }
14201     if(stat == TNG_CRITICAL)
14202     {
14203         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14204                file_pos, __FILE__, __LINE__);
14205         tng_block_destroy(&block);
14206         tng_data->input_file = temp;
14207         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14208         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14209         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14210         return(stat);
14211     }
14212
14213     contents_size = block->block_contents_size;
14214     header_size = block->header_contents_size;
14215
14216     header_pos = ftell(tng_data->output_file) - header_size;
14217     frame_set = &tng_data->current_trajectory_frame_set;
14218
14219     if(fread(&datatype, sizeof(datatype), 1, tng_data->input_file) == 0)
14220     {
14221         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14222         tng_block_destroy(&block);
14223         return(TNG_CRITICAL);
14224     }
14225     if(fread(&dependency, sizeof(dependency), 1, tng_data->input_file) == 0)
14226     {
14227         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14228         tng_block_destroy(&block);
14229         return(TNG_CRITICAL);
14230     }
14231     data.datatype = datatype;
14232
14233     if(!(dependency & TNG_FRAME_DEPENDENT) ||
14234        (dependency & TNG_PARTICLE_DEPENDENT))
14235     {
14236         tng_block_destroy(&block);
14237         tng_data->input_file = temp;
14238
14239         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14240         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14241         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14242         return(TNG_FAILURE);
14243     }
14244
14245     if(fread(&sparse_data, sizeof(sparse_data), 1, tng_data->input_file) == 0)
14246     {
14247         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14248         tng_block_destroy(&block);
14249         return(TNG_CRITICAL);
14250     }
14251
14252     if(fread(&data.n_values_per_frame, sizeof(data.n_values_per_frame), 1,
14253              tng_data->input_file) == 0)
14254     {
14255         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14256         tng_block_destroy(&block);
14257         return(TNG_CRITICAL);
14258     }
14259     if(tng_data->output_endianness_swap_func_64)
14260     {
14261         if(tng_data->output_endianness_swap_func_64(tng_data,
14262             &data.n_values_per_frame)
14263             != TNG_SUCCESS)
14264         {
14265             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14266                     __FILE__, __LINE__);
14267         }
14268     }
14269
14270     if(fread(&data.codec_id, sizeof(data.codec_id), 1,
14271              tng_data->input_file) == 0)
14272     {
14273         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14274         tng_block_destroy(&block);
14275         return(TNG_CRITICAL);
14276     }
14277     if(tng_data->output_endianness_swap_func_64)
14278     {
14279         if(tng_data->output_endianness_swap_func_64(tng_data,
14280             &data.codec_id)
14281             != TNG_SUCCESS)
14282         {
14283             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14284                     __FILE__, __LINE__);
14285         }
14286     }
14287
14288     if(data.codec_id != TNG_UNCOMPRESSED)
14289     {
14290         if(fread(&data.compression_multiplier,
14291                  sizeof(data.compression_multiplier), 1, tng_data->input_file)
14292             == 0)
14293         {
14294             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14295             tng_block_destroy(&block);
14296             return(TNG_CRITICAL);
14297         }
14298         if(tng_data->output_endianness_swap_func_64)
14299         {
14300             if(tng_data->output_endianness_swap_func_64(tng_data,
14301                 (int64_t *)&data.compression_multiplier)
14302                 != TNG_SUCCESS)
14303             {
14304                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14305                         __FILE__, __LINE__);
14306             }
14307         }
14308     }
14309     else
14310     {
14311         data.compression_multiplier = 1;
14312     }
14313
14314     if(sparse_data)
14315     {
14316         if(fread(&data.first_frame_with_data, sizeof(data.first_frame_with_data),
14317                  1, tng_data->input_file) == 0)
14318         {
14319             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14320             tng_block_destroy(&block);
14321             return(TNG_CRITICAL);
14322         }
14323         if(tng_data->output_endianness_swap_func_64)
14324         {
14325             if(tng_data->output_endianness_swap_func_64(tng_data,
14326                 &data.first_frame_with_data)
14327                 != TNG_SUCCESS)
14328             {
14329                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14330                         __FILE__, __LINE__);
14331             }
14332         }
14333
14334         if(fread(&data.stride_length, sizeof(data.stride_length),
14335                  1, tng_data->input_file) == 0)
14336         {
14337             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14338             tng_block_destroy(&block);
14339             return(TNG_CRITICAL);
14340         }
14341         if(tng_data->output_endianness_swap_func_64)
14342         {
14343             if(tng_data->output_endianness_swap_func_64(tng_data,
14344                 &data.stride_length)
14345                 != TNG_SUCCESS)
14346             {
14347                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14348                         __FILE__, __LINE__);
14349             }
14350         }
14351     }
14352     else
14353     {
14354         data.first_frame_with_data = 0;
14355         data.stride_length = 1;
14356     }
14357     data.n_frames = tng_data->current_trajectory_frame_set.n_frames;
14358
14359     tng_data->input_file = temp;
14360
14361     tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14362     tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14363     tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14364
14365     switch(data.datatype)
14366     {
14367         case(TNG_INT_DATA):
14368             size = sizeof(int64_t);
14369             break;
14370         case(TNG_FLOAT_DATA):
14371             size = sizeof(float);
14372             break;
14373         case(TNG_DOUBLE_DATA):
14374             size = sizeof(double);
14375             break;
14376         default:
14377             fprintf(stderr, "TNG library: Cannot calculate writing locations. %s: %d.\n", __FILE__,
14378                    __LINE__);
14379             tng_block_destroy(&block);
14380             return(TNG_FAILURE);
14381     }
14382
14383     n_values_per_frame = data.n_values_per_frame;
14384
14385     file_pos = (frame_nr - tng_max_i64(frame_set->first_frame,
14386                                data.first_frame_with_data)) /
14387                 data.stride_length;
14388     file_pos *= size * n_values_per_frame;
14389
14390     if(file_pos > contents_size)
14391     {
14392         fprintf(stderr, "TNG library: Attempting to write outside the block. %s: %d\n", __FILE__,
14393                __LINE__);
14394         tng_block_destroy(&block);
14395         return(TNG_FAILURE);
14396     }
14397
14398     fseek(tng_data->output_file, (long)file_pos, SEEK_CUR);
14399
14400     /* If the endianness is not big endian the data needs to be swapped */
14401     if((data.datatype == TNG_INT_DATA ||
14402         data.datatype == TNG_DOUBLE_DATA) &&
14403        tng_data->output_endianness_swap_func_64)
14404     {
14405         copy = malloc(n_values_per_frame * size);
14406         memcpy(copy, values, n_values_per_frame * size);
14407         for(i = 0; i < n_values_per_frame; i++)
14408         {
14409             if(tng_data->output_endianness_swap_func_64(tng_data,
14410                 (int64_t *)copy+i)
14411                 != TNG_SUCCESS)
14412             {
14413                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14414                         __FILE__, __LINE__);
14415             }
14416         }
14417         fwrite(copy, n_values_per_frame, size,
14418                tng_data->output_file);
14419         free(copy);
14420     }
14421     else if(data.datatype == TNG_FLOAT_DATA &&
14422             tng_data->output_endianness_swap_func_32)
14423     {
14424         copy = malloc(n_values_per_frame * size);
14425         memcpy(copy, values, n_values_per_frame * size);
14426         for(i = 0; i < n_values_per_frame; i++)
14427         {
14428             if(tng_data->output_endianness_swap_func_32(tng_data,
14429                 (int32_t *)copy+i)
14430                 != TNG_SUCCESS)
14431             {
14432                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14433                         __FILE__, __LINE__);
14434             }
14435         }
14436         fwrite(copy, n_values_per_frame, size,
14437                tng_data->output_file);
14438         free(copy);
14439     }
14440
14441     else
14442     {
14443         fwrite(values, n_values_per_frame, size, tng_data->output_file);
14444     }
14445
14446     fflush(tng_data->output_file);
14447
14448     /* Update the number of written frames in the frame set. */
14449     if(frame_nr - frame_set->first_frame + 1 > frame_set->n_written_frames)
14450     {
14451         frame_set->n_written_frames = frame_nr - frame_set->first_frame + 1;
14452     }
14453
14454     /* If the last frame has been written update the hash */
14455     if(hash_mode == TNG_USE_HASH && (frame_nr + data.stride_length -
14456        data.first_frame_with_data) >=
14457        frame_set->n_frames)
14458     {
14459         tng_md5_hash_update(tng_data, block, header_pos, header_pos +
14460                             header_size);
14461     }
14462
14463     tng_block_destroy(&block);
14464
14465     return(TNG_SUCCESS);
14466 }
14467
14468 tng_function_status DECLSPECDLLEXPORT tng_frame_particle_data_write
14469                 (tng_trajectory_t tng_data,
14470                  const int64_t frame_nr,
14471                  const int64_t block_id,
14472                  const int64_t val_first_particle,
14473                  const int64_t val_n_particles,
14474                  const void *values,
14475                  const char hash_mode)
14476 {
14477     int64_t header_pos, file_pos, tot_n_particles;
14478     int64_t output_file_len, n_values_per_frame, size, contents_size;
14479     int64_t header_size, temp_first, temp_last;
14480     int64_t mapping_block_end_pos, num_first_particle, block_n_particles;
14481     int64_t i, last_frame;
14482     long temp_current;
14483     tng_gen_block_t block;
14484     tng_trajectory_frame_set_t frame_set;
14485     FILE *temp = tng_data->input_file;
14486     struct tng_particle_data data;
14487     tng_function_status stat;
14488     tng_particle_mapping_t mapping;
14489     char dependency, sparse_data, datatype;
14490     void *copy;
14491
14492     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14493     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
14494     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer.");
14495     TNG_ASSERT(val_first_particle >= 0, "TNG library: val_first_particle must be >= 0.");
14496     TNG_ASSERT(val_n_particles >= 0, "TNG library: val_n_particles must be >= 0.");
14497
14498     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
14499     {
14500         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
14501                __FILE__, __LINE__);
14502         return(TNG_CRITICAL);
14503     }
14504
14505     temp_first = tng_data->first_trajectory_frame_set_input_file_pos;
14506     temp_last = tng_data->last_trajectory_frame_set_input_file_pos;
14507     temp_current = tng_data->current_trajectory_frame_set_input_file_pos;
14508     tng_data->first_trajectory_frame_set_input_file_pos =
14509     tng_data->first_trajectory_frame_set_output_file_pos;
14510     tng_data->last_trajectory_frame_set_input_file_pos =
14511     tng_data->last_trajectory_frame_set_output_file_pos;
14512     tng_data->current_trajectory_frame_set_input_file_pos =
14513     tng_data->current_trajectory_frame_set_output_file_pos;
14514
14515     tng_data->input_file = tng_data->output_file;
14516
14517     stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
14518
14519     frame_set = &tng_data->current_trajectory_frame_set;
14520
14521     if(stat != TNG_SUCCESS)
14522     {
14523         last_frame = frame_set->first_frame +
14524                      frame_set->n_frames - 1;
14525 /*         fprintf(stderr, "TNG library: Frame %"PRId64" not found. Last frame: %"PRId64"\n", frame_nr,
14526                   last_frame); */
14527         /* If the wanted frame would be in the frame set after the last
14528          * frame set create a new frame set. */
14529         if(stat == TNG_FAILURE &&
14530            (last_frame < frame_nr &&
14531             last_frame + tng_data->frame_set_n_frames >= frame_nr))
14532         {
14533             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
14534             {
14535                 last_frame = frame_nr - 1;
14536             }
14537             tng_frame_set_new(tng_data,
14538                               last_frame+1,
14539                               tng_data->frame_set_n_frames);
14540
14541             file_pos = ftell(tng_data->output_file);
14542             fseek(tng_data->output_file, 0, SEEK_END);
14543             output_file_len = ftell(tng_data->output_file);
14544             fseek(tng_data->output_file, (long)file_pos, SEEK_SET);
14545
14546             /* Read mapping blocks from the last frame set */
14547             tng_block_init(&block);
14548
14549             stat = tng_block_header_read(tng_data, block);
14550             while(file_pos < output_file_len &&
14551                   stat != TNG_CRITICAL &&
14552                   block->id != TNG_TRAJECTORY_FRAME_SET &&
14553                   block->id != -1)
14554             {
14555                 if(block->id == TNG_PARTICLE_MAPPING)
14556                 {
14557                     tng_trajectory_mapping_block_read(tng_data, block,
14558                                                       hash_mode);
14559                 }
14560                 else
14561                 {
14562                     fseek(tng_data->output_file, (long)block->block_contents_size,
14563                         SEEK_CUR);
14564                 }
14565                 file_pos = ftell(tng_data->output_file);
14566                 if(file_pos < output_file_len)
14567                 {
14568                     stat = tng_block_header_read(tng_data, block);
14569                 }
14570             }
14571
14572             tng_block_destroy(&block);
14573             /* Write the frame set to disk */
14574             if(tng_frame_set_write(tng_data, hash_mode) != TNG_SUCCESS)
14575             {
14576                 fprintf(stderr, "TNG library: Error writing frame set. %s: %d\n", __FILE__, __LINE__);
14577                 exit(1);
14578             }
14579         }
14580         else
14581         {
14582             tng_data->input_file = temp;
14583             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14584             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14585             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14586             return(stat);
14587         }
14588     }
14589
14590
14591     tng_block_init(&block);
14592
14593     file_pos = tng_data->current_trajectory_frame_set_output_file_pos;
14594
14595     fseek(tng_data->output_file, 0, SEEK_END);
14596     output_file_len = ftell(tng_data->output_file);
14597     fseek(tng_data->output_file, (long)file_pos, SEEK_SET);
14598
14599     /* Read past the frame set block first */
14600     stat = tng_block_header_read(tng_data, block);
14601     if(stat == TNG_CRITICAL)
14602     {
14603         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14604                file_pos, __FILE__, __LINE__);
14605         tng_block_destroy(&block);
14606         tng_data->input_file = temp;
14607
14608         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14609         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14610         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14611         return(stat);
14612     }
14613     fseek(tng_data->output_file, (long)block->block_contents_size,
14614             SEEK_CUR);
14615
14616     if(tng_data->var_num_atoms_flag)
14617     {
14618         tot_n_particles = frame_set->n_particles;
14619     }
14620     else
14621     {
14622         tot_n_particles = tng_data->n_particles;
14623     }
14624
14625     if(val_n_particles < tot_n_particles)
14626     {
14627         mapping_block_end_pos = -1;
14628         /* Read all mapping blocks to find the right place to put the data */
14629         stat = tng_block_header_read(tng_data, block);
14630         while(file_pos < output_file_len &&
14631                 stat != TNG_CRITICAL &&
14632                 block->id != TNG_TRAJECTORY_FRAME_SET &&
14633                 block->id != -1)
14634         {
14635             if(block->id == TNG_PARTICLE_MAPPING)
14636             {
14637                 tng_trajectory_mapping_block_read(tng_data, block, hash_mode);
14638             }
14639             else
14640             {
14641                 fseek(tng_data->output_file, (long)block->block_contents_size,
14642                       SEEK_CUR);
14643             }
14644             file_pos = ftell(tng_data->output_file);
14645             if(block->id == TNG_PARTICLE_MAPPING)
14646             {
14647                 mapping = &frame_set->mappings[frame_set->n_mapping_blocks - 1];
14648                 if(val_first_particle >= mapping->num_first_particle &&
14649                    val_first_particle < mapping->num_first_particle +
14650                    mapping->n_particles &&
14651                    val_first_particle + val_n_particles <=
14652                    mapping->num_first_particle + mapping->n_particles)
14653                 {
14654                     mapping_block_end_pos = file_pos;
14655                 }
14656             }
14657             if(file_pos < output_file_len)
14658             {
14659                 stat = tng_block_header_read(tng_data, block);
14660             }
14661         }
14662         if(stat == TNG_CRITICAL)
14663         {
14664             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14665                    file_pos, __FILE__, __LINE__);
14666             tng_block_destroy(&block);
14667             tng_data->input_file = temp;
14668
14669             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14670             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14671             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14672             return(stat);
14673         }
14674         if(mapping_block_end_pos < 0)
14675         {
14676             tng_block_destroy(&block);
14677             tng_data->input_file = temp;
14678
14679             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14680             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14681             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14682             return(TNG_FAILURE);
14683         }
14684         fseek(tng_data->output_file, (long)mapping_block_end_pos, SEEK_SET);
14685     }
14686
14687     /* Read all block headers until next frame set block or
14688      * until the wanted block id is found */
14689     stat = tng_block_header_read(tng_data, block);
14690     while(file_pos < output_file_len &&
14691             stat != TNG_CRITICAL &&
14692             block->id != block_id &&
14693             block->id != TNG_PARTICLE_MAPPING &&
14694             block->id != TNG_TRAJECTORY_FRAME_SET &&
14695             block->id != -1)
14696     {
14697         fseek(tng_data->output_file, (long)block->block_contents_size, SEEK_CUR);
14698         file_pos = ftell(tng_data->output_file);
14699         if(file_pos < output_file_len)
14700         {
14701             stat = tng_block_header_read(tng_data, block);
14702         }
14703     }
14704     if(stat == TNG_CRITICAL)
14705     {
14706         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14707                 file_pos, __FILE__, __LINE__);
14708         tng_block_destroy(&block);
14709         tng_data->input_file = temp;
14710
14711         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14712         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14713         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14714         return(stat);
14715     }
14716
14717     contents_size = block->block_contents_size;
14718     header_size = block->header_contents_size;
14719
14720     header_pos = ftell(tng_data->output_file) - header_size;
14721     frame_set = &tng_data->current_trajectory_frame_set;
14722
14723     if(fread(&datatype, sizeof(datatype), 1, tng_data->input_file) == 0)
14724     {
14725         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14726         tng_block_destroy(&block);
14727         return(TNG_CRITICAL);
14728     }
14729
14730     data.datatype = datatype;
14731
14732     if(fread(&dependency, sizeof(dependency), 1, tng_data->input_file) == 0)
14733     {
14734         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14735         tng_block_destroy(&block);
14736         return(TNG_CRITICAL);
14737     }
14738
14739     if(!(dependency & TNG_FRAME_DEPENDENT) ||
14740        !(dependency & TNG_PARTICLE_DEPENDENT))
14741     {
14742         tng_block_destroy(&block);
14743         tng_data->input_file = temp;
14744
14745         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14746         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14747         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14748         return(TNG_FAILURE);
14749     }
14750
14751     if(fread(&sparse_data, sizeof(sparse_data), 1, tng_data->input_file) == 0)
14752     {
14753         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14754         tng_block_destroy(&block);
14755         return(TNG_CRITICAL);
14756     }
14757
14758     if(fread(&data.n_values_per_frame, sizeof(data.n_values_per_frame), 1,
14759              tng_data->input_file) == 0)
14760     {
14761         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14762         tng_block_destroy(&block);
14763         return(TNG_CRITICAL);
14764     }
14765     if(tng_data->output_endianness_swap_func_64)
14766     {
14767         if(tng_data->output_endianness_swap_func_64(tng_data,
14768             &data.n_values_per_frame)
14769             != TNG_SUCCESS)
14770         {
14771             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14772                     __FILE__, __LINE__);
14773         }
14774     }
14775
14776     if(fread(&data.codec_id, sizeof(data.codec_id), 1,
14777              tng_data->input_file) == 0)
14778     {
14779         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14780         tng_block_destroy(&block);
14781         return(TNG_CRITICAL);
14782     }
14783     if(tng_data->output_endianness_swap_func_64)
14784     {
14785         if(tng_data->output_endianness_swap_func_64(tng_data,
14786             &data.codec_id)
14787             != TNG_SUCCESS)
14788         {
14789             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14790                     __FILE__, __LINE__);
14791         }
14792     }
14793
14794     if(data.codec_id != TNG_UNCOMPRESSED)
14795     {
14796         if(fread(&data.compression_multiplier,
14797                  sizeof(data.compression_multiplier), 1, tng_data->input_file)
14798             == 0)
14799         {
14800             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14801             tng_block_destroy(&block);
14802             return(TNG_CRITICAL);
14803         }
14804
14805         if(tng_data->output_endianness_swap_func_64)
14806         {
14807             if(tng_data->output_endianness_swap_func_64(tng_data,
14808                (int64_t *)&data.compression_multiplier)
14809                 != TNG_SUCCESS)
14810             {
14811                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14812                         __FILE__, __LINE__);
14813             }
14814         }
14815     }
14816     else
14817     {
14818         data.compression_multiplier = 1;
14819     }
14820
14821     if(sparse_data)
14822     {
14823         if(fread(&data.first_frame_with_data,
14824                  sizeof(data.first_frame_with_data),
14825                  1, tng_data->input_file) == 0)
14826         {
14827             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14828             tng_block_destroy(&block);
14829             return(TNG_CRITICAL);
14830         }
14831         if(tng_data->output_endianness_swap_func_64)
14832         {
14833             if(tng_data->output_endianness_swap_func_64(tng_data,
14834                 &data.first_frame_with_data)
14835                 != TNG_SUCCESS)
14836             {
14837                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14838                         __FILE__, __LINE__);
14839             }
14840         }
14841
14842         if(fread(&data.stride_length, sizeof(data.stride_length),
14843                  1, tng_data->input_file) == 0)
14844         {
14845             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14846             tng_block_destroy(&block);
14847             return(TNG_CRITICAL);
14848         }
14849         if(tng_data->output_endianness_swap_func_64)
14850         {
14851             if(tng_data->output_endianness_swap_func_64(tng_data,
14852                 &data.stride_length)
14853                 != TNG_SUCCESS)
14854             {
14855                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14856                         __FILE__, __LINE__);
14857             }
14858         }
14859     }
14860     else
14861     {
14862         data.first_frame_with_data = 0;
14863         data.stride_length = 1;
14864     }
14865     data.n_frames = tng_data->current_trajectory_frame_set.n_frames;
14866
14867     if(fread(&num_first_particle, sizeof(num_first_particle), 1,
14868              tng_data->input_file) == 0)
14869     {
14870         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14871         tng_block_destroy(&block);
14872         return(TNG_CRITICAL);
14873     }
14874     if(tng_data->output_endianness_swap_func_64)
14875     {
14876         if(tng_data->output_endianness_swap_func_64(tng_data,
14877             &num_first_particle)
14878             != TNG_SUCCESS)
14879         {
14880             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14881                     __FILE__, __LINE__);
14882         }
14883     }
14884
14885     if(fread(&block_n_particles, sizeof(block_n_particles), 1,
14886              tng_data->input_file) == 0)
14887     {
14888         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14889         tng_block_destroy(&block);
14890         return(TNG_CRITICAL);
14891     }
14892     if(tng_data->output_endianness_swap_func_64)
14893     {
14894         if(tng_data->output_endianness_swap_func_64(tng_data,
14895             &block_n_particles)
14896             != TNG_SUCCESS)
14897         {
14898             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14899                     __FILE__, __LINE__);
14900         }
14901     }
14902
14903
14904     tng_data->input_file = temp;
14905
14906     tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14907     tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14908     tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14909
14910
14911     switch(data.datatype)
14912     {
14913         case(TNG_INT_DATA):
14914             size = sizeof(int64_t);
14915             break;
14916         case(TNG_FLOAT_DATA):
14917             size = sizeof(float);
14918             break;
14919         case(TNG_DOUBLE_DATA):
14920             size = sizeof(double);
14921             break;
14922         default:
14923             fprintf(stderr, "TNG library: Cannot calculate writing locations. %s: %d.\n", __FILE__,
14924                    __LINE__);
14925             tng_block_destroy(&block);
14926             return(TNG_FAILURE);
14927     }
14928
14929     n_values_per_frame = data.n_values_per_frame;
14930
14931     file_pos = (frame_nr - tng_max_i64(frame_set->first_frame,
14932                                data.first_frame_with_data)) /
14933                 data.stride_length;
14934     file_pos *= block_n_particles * size * n_values_per_frame;
14935
14936     if(file_pos > contents_size)
14937     {
14938         fprintf(stderr, "TNG library: Attempting to write outside the block. %s: %d\n", __FILE__,
14939                __LINE__);
14940         tng_block_destroy(&block);
14941         return(TNG_FAILURE);
14942     }
14943
14944     fseek(tng_data->output_file, (long)file_pos, SEEK_CUR);
14945
14946     /* If the endianness is not big endian the data needs to be swapped */
14947     if((data.datatype == TNG_INT_DATA ||
14948         data.datatype == TNG_DOUBLE_DATA) &&
14949        tng_data->output_endianness_swap_func_64)
14950     {
14951         copy = malloc(val_n_particles * n_values_per_frame * size);
14952         memcpy(copy, values, val_n_particles * n_values_per_frame * size);
14953         for(i = 0; i < val_n_particles * n_values_per_frame; i++)
14954         {
14955             if(tng_data->output_endianness_swap_func_64(tng_data,
14956                 (int64_t *) copy+i)
14957                 != TNG_SUCCESS)
14958             {
14959                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14960                         __FILE__, __LINE__);
14961             }
14962         }
14963         fwrite(copy, val_n_particles * n_values_per_frame, size,
14964                tng_data->output_file);
14965         free(copy);
14966     }
14967     else if(data.datatype == TNG_FLOAT_DATA &&
14968        tng_data->output_endianness_swap_func_32)
14969     {
14970         copy = malloc(val_n_particles * n_values_per_frame * size);
14971         memcpy(copy, values, val_n_particles * n_values_per_frame * size);
14972         for(i = 0; i < val_n_particles * n_values_per_frame; i++)
14973         {
14974             if(tng_data->output_endianness_swap_func_32(tng_data,
14975                 (int32_t *) copy+i)
14976                 != TNG_SUCCESS)
14977             {
14978                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14979                         __FILE__, __LINE__);
14980             }
14981         }
14982         fwrite(copy, val_n_particles * n_values_per_frame, size,
14983                tng_data->output_file);
14984         free(copy);
14985     }
14986
14987     else
14988     {
14989         fwrite(values, val_n_particles * n_values_per_frame, size,
14990                tng_data->output_file);
14991     }
14992     fflush(tng_data->output_file);
14993
14994     /* Update the number of written frames in the frame set. */
14995     if(frame_nr - frame_set->first_frame + 1 > frame_set->n_written_frames)
14996     {
14997         frame_set->n_written_frames = frame_nr - frame_set->first_frame + 1;
14998     }
14999
15000     /* If the last frame has been written update the hash */
15001     if(hash_mode == TNG_USE_HASH && (frame_nr + data.stride_length -
15002        data.first_frame_with_data) >=
15003        frame_set->n_frames)
15004     {
15005         tng_md5_hash_update(tng_data, block, header_pos, header_pos +
15006                             header_size);
15007     }
15008
15009     tng_block_destroy(&block);
15010     return(TNG_SUCCESS);
15011 }
15012
15013 static tng_function_status tng_data_values_alloc
15014                 (const tng_trajectory_t tng_data,
15015                  union data_values ***values,
15016                  const int64_t n_frames,
15017                  const int64_t n_values_per_frame,
15018                  const char type)
15019 {
15020     int64_t i;
15021     tng_function_status stat;
15022
15023     if(n_frames <= 0 || n_values_per_frame <= 0)
15024     {
15025         return(TNG_FAILURE);
15026     }
15027
15028     if(*values)
15029     {
15030         stat = tng_data_values_free(tng_data, *values, n_frames,
15031                                     n_values_per_frame,
15032                                     type);
15033         if(stat != TNG_SUCCESS)
15034         {
15035             fprintf(stderr, "TNG library: Cannot free particle data values. %s: %d\n",
15036                    __FILE__, __LINE__);
15037             return(stat);
15038         }
15039     }
15040     *values = malloc(sizeof(union data_values *) * n_frames);
15041     if(!*values)
15042     {
15043         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15044                sizeof(union data_values **) * n_frames,
15045                __FILE__, __LINE__);
15046         return(TNG_CRITICAL);
15047
15048     }
15049
15050     for(i = 0; i < n_frames; i++)
15051     {
15052         (*values)[i] = malloc(sizeof(union data_values) *
15053                            n_values_per_frame);
15054         if(!(*values)[i])
15055         {
15056             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15057                    sizeof(union data_values) * n_values_per_frame,
15058                    __FILE__, __LINE__);
15059             free(values);
15060             values = 0;
15061             return(TNG_CRITICAL);
15062         }
15063     }
15064     return(TNG_SUCCESS);
15065 }
15066
15067 /* FIXME: This needs ***values */
15068 tng_function_status DECLSPECDLLEXPORT tng_data_values_free
15069                 (const tng_trajectory_t tng_data,
15070                  union data_values **values,
15071                  const int64_t n_frames,
15072                  const int64_t n_values_per_frame,
15073                  const char type)
15074 {
15075     int64_t i, j;
15076     (void)tng_data;
15077
15078     if(values)
15079     {
15080         for(i = 0; i < n_frames; i++)
15081         {
15082             if(values[i])
15083             {
15084                 if(type == TNG_CHAR_DATA)
15085                 {
15086                     for(j = 0; j < n_values_per_frame; j++)
15087                     {
15088                         if(values[i][j].c)
15089                         {
15090                             free(values[i][j].c);
15091                             values[i][j].c = 0;
15092                         }
15093                     }
15094                 }
15095                 free(values[i]);
15096                 values[i] = 0;
15097             }
15098         }
15099         free(values);
15100         values = 0;
15101     }
15102
15103     return(TNG_SUCCESS);
15104 }
15105
15106 static tng_function_status tng_particle_data_values_alloc
15107                 (const tng_trajectory_t tng_data,
15108                  union data_values ****values,
15109                  const int64_t n_frames,
15110                  const int64_t n_particles,
15111                  const int64_t n_values_per_frame,
15112                  const char type)
15113 {
15114     int64_t i, j;
15115     tng_function_status stat;
15116
15117     if(n_particles == 0 || n_values_per_frame == 0)
15118     {
15119         return(TNG_FAILURE);
15120     }
15121
15122     if(*values)
15123     {
15124         stat = tng_particle_data_values_free(tng_data, *values, n_frames,
15125                                              n_particles, n_values_per_frame,
15126                                              type);
15127         if(stat != TNG_SUCCESS)
15128         {
15129             fprintf(stderr, "TNG library: Cannot free particle data values. %s: %d\n",
15130                    __FILE__, __LINE__);
15131             return(stat);
15132         }
15133     }
15134     *values = malloc(sizeof(union data_values **) * n_frames);
15135     if(!*values)
15136     {
15137         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15138                sizeof(union data_values **) * n_frames,
15139                __FILE__, __LINE__);
15140         return(TNG_CRITICAL);
15141
15142     }
15143
15144     for(i = 0; i < n_frames; i++)
15145     {
15146         (*values)[i] = malloc(sizeof(union data_values *) *
15147                            n_particles);
15148         if(!(*values)[i])
15149         {
15150             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15151                    sizeof(union data_values *) * n_particles,
15152                    __FILE__, __LINE__);
15153             free(*values);
15154             *values = 0;
15155             return(TNG_CRITICAL);
15156         }
15157         for(j = 0; j < n_particles; j++)
15158         {
15159             (*values)[i][j] = malloc(sizeof(union data_values) *
15160                                   n_values_per_frame);
15161             if(!(*values)[i][j])
15162             {
15163                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15164                     sizeof(union data_values *) * n_particles,
15165                     __FILE__, __LINE__);
15166                 tng_particle_data_values_free(tng_data, *values, n_frames,
15167                                               n_particles, n_values_per_frame,
15168                                               type);
15169                 *values = 0;
15170                 return(TNG_CRITICAL);
15171             }
15172         }
15173     }
15174     return(TNG_SUCCESS);
15175 }
15176
15177 /* FIXME: This needs ****values */
15178 tng_function_status DECLSPECDLLEXPORT tng_particle_data_values_free
15179                 (const tng_trajectory_t tng_data,
15180                  union data_values ***values,
15181                  const int64_t n_frames,
15182                  const int64_t n_particles,
15183                  const int64_t n_values_per_frame,
15184                  const char type)
15185 {
15186     int64_t i, j, k;
15187     (void)tng_data;
15188
15189     if(values)
15190     {
15191         for(i = 0; i < n_frames; i++)
15192         {
15193             if(values[i])
15194             {
15195                 for(j = 0; j < n_particles; j++)
15196                 {
15197                     if(type == TNG_CHAR_DATA)
15198                     {
15199                         for(k = 0; k < n_values_per_frame; k++)
15200                         {
15201                             if(values[i][j][k].c)
15202                             {
15203                                 free(values[i][j][k].c);
15204                                 values[i][j][k].c = 0;
15205                             }
15206                         }
15207                     }
15208                     free(values[i][j]);
15209                     values[i][j] = 0;
15210                 }
15211                 free(values[i]);
15212                 values[i] = 0;
15213             }
15214         }
15215         free(values);
15216         values = 0;
15217     }
15218
15219     return(TNG_SUCCESS);
15220 }
15221
15222
15223 tng_function_status DECLSPECDLLEXPORT tng_data_get
15224                 (tng_trajectory_t tng_data,
15225                  const int64_t block_id,
15226                  union data_values ***values,
15227                  int64_t *n_frames,
15228                  int64_t *n_values_per_frame,
15229                  char *type)
15230 {
15231     int64_t i, j, file_pos, block_index;
15232     int size;
15233     size_t len;
15234     tng_non_particle_data_t data;
15235     tng_trajectory_frame_set_t frame_set;
15236     tng_gen_block_t block;
15237     tng_function_status stat;
15238
15239     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15240     TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
15241     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15242     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15243
15244     frame_set = &tng_data->current_trajectory_frame_set;
15245
15246     block_index = -1;
15247     data = 0;
15248
15249     if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
15250     {
15251         tng_block_init(&block);
15252         file_pos = ftell(tng_data->input_file);
15253         /* Read all blocks until next frame set block */
15254         stat = tng_block_header_read(tng_data, block);
15255         while(file_pos < tng_data->input_file_len &&
15256                 stat != TNG_CRITICAL &&
15257                 block->id != TNG_TRAJECTORY_FRAME_SET &&
15258                 block->id != -1)
15259         {
15260             /* Use hash by default */
15261             stat = tng_block_read_next(tng_data, block,
15262                                     TNG_USE_HASH);
15263             if(stat != TNG_CRITICAL)
15264             {
15265                 file_pos = ftell(tng_data->input_file);
15266                 if(file_pos < tng_data->input_file_len)
15267                 {
15268                     stat = tng_block_header_read(tng_data, block);
15269                 }
15270             }
15271         }
15272         tng_block_destroy(&block);
15273         if(stat == TNG_CRITICAL)
15274         {
15275             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15276                     file_pos, __FILE__, __LINE__);
15277             return(stat);
15278         }
15279
15280         for(i = 0; i < frame_set->n_data_blocks; i++)
15281         {
15282             data = &frame_set->tr_data[i];
15283             if(data->block_id == block_id)
15284             {
15285                 block_index = i;
15286                 break;
15287             }
15288         }
15289         if(block_index < 0)
15290         {
15291             return(TNG_FAILURE);
15292         }
15293     }
15294
15295     *n_frames = tng_max_i64(1, data->n_frames);
15296     *n_values_per_frame = data->n_values_per_frame;
15297     *type = data->datatype;
15298
15299     if(*values == 0)
15300     {
15301         if(tng_data_values_alloc(tng_data, values, *n_frames,
15302                                  *n_values_per_frame,
15303                                  *type)
15304         != TNG_SUCCESS)
15305         {
15306             return(TNG_CRITICAL);
15307         }
15308     }
15309
15310     switch(*type)
15311     {
15312     case TNG_CHAR_DATA:
15313         for(i = 0; i < *n_frames; i++)
15314         {
15315             for(j = 0; j < *n_values_per_frame; j++)
15316             {
15317                 len = strlen(data->strings[i][j]) + 1;
15318                 (*values)[i][j].c = malloc(len);
15319                 strncpy((*values)[i][j].c, data->strings[i][j], len);
15320             }
15321         }
15322         break;
15323     case TNG_INT_DATA:
15324         size = sizeof(int);
15325         for(i = 0; i < *n_frames; i++)
15326         {
15327             for(j = 0; j < *n_values_per_frame; j++)
15328             {
15329                 (*values)[i][j].i = *(int *)((char *)data->values + size *
15330                                              (i*(*n_values_per_frame) + j));
15331             }
15332         }
15333         break;
15334     case TNG_FLOAT_DATA:
15335         size = sizeof(float);
15336         for(i = 0; i < *n_frames; i++)
15337         {
15338             for(j = 0; j < *n_values_per_frame; j++)
15339             {
15340                 (*values)[i][j].f = *(float *)((char *)data->values + size *
15341                                                (i*(*n_values_per_frame) + j));
15342             }
15343         }
15344         break;
15345     case TNG_DOUBLE_DATA:
15346     default:
15347         size = sizeof(double);
15348         for(i = 0; i < *n_frames; i++)
15349         {
15350             for(j = 0; j < *n_values_per_frame; j++)
15351             {
15352                 (*values)[i][j].d = *(double *)((char *)data->values + size *
15353                                                 (i*(*n_values_per_frame) + j));
15354             }
15355         }
15356     }
15357
15358     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
15359
15360     return(TNG_SUCCESS);
15361 }
15362
15363 tng_function_status tng_data_vector_get(tng_trajectory_t tng_data,
15364                                         const int64_t block_id,
15365                                         void **values,
15366                                         int64_t *n_frames,
15367                                         int64_t *stride_length,
15368                                         int64_t *n_values_per_frame,
15369                                         char *type)
15370 {
15371     int64_t file_pos, data_size, n_frames_div, block_index;
15372     int i, size;
15373     tng_non_particle_data_t data;
15374     tng_trajectory_frame_set_t frame_set;
15375     tng_gen_block_t block;
15376     void *temp;
15377     tng_function_status stat;
15378
15379     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15380     TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
15381     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
15382     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15383     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15384
15385     frame_set = &tng_data->current_trajectory_frame_set;
15386
15387     block_index = -1;
15388     data = 0;
15389
15390     if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
15391     {
15392         tng_block_init(&block);
15393         file_pos = ftell(tng_data->input_file);
15394         /* Read all blocks until next frame set block */
15395         stat = tng_block_header_read(tng_data, block);
15396         while(file_pos < tng_data->input_file_len &&
15397                 stat != TNG_CRITICAL &&
15398                 block->id != TNG_TRAJECTORY_FRAME_SET &&
15399                 block->id != -1)
15400         {
15401             /* Use hash by default */
15402             stat = tng_block_read_next(tng_data, block,
15403                                     TNG_USE_HASH);
15404             if(stat != TNG_CRITICAL)
15405             {
15406                 file_pos = ftell(tng_data->input_file);
15407                 if(file_pos < tng_data->input_file_len)
15408                 {
15409                     stat = tng_block_header_read(tng_data, block);
15410                 }
15411             }
15412         }
15413         tng_block_destroy(&block);
15414         if(stat == TNG_CRITICAL)
15415         {
15416             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15417                     file_pos, __FILE__, __LINE__);
15418             return(stat);
15419         }
15420
15421         for(i = 0; i < frame_set->n_data_blocks; i++)
15422         {
15423             data = &frame_set->tr_data[i];
15424             if(data->block_id == block_id)
15425             {
15426                 block_index = i;
15427                 break;
15428             }
15429         }
15430         if(block_index < 0)
15431         {
15432             return(TNG_FAILURE);
15433         }
15434     }
15435
15436     *type = data->datatype;
15437
15438     switch(*type)
15439     {
15440     case TNG_CHAR_DATA:
15441         return(TNG_FAILURE);
15442     case TNG_INT_DATA:
15443         size = sizeof(int64_t);
15444         break;
15445     case TNG_FLOAT_DATA:
15446         size = sizeof(float);
15447         break;
15448     case TNG_DOUBLE_DATA:
15449     default:
15450         size = sizeof(double);
15451     }
15452
15453     *n_frames = data->n_frames;
15454     *n_values_per_frame = data->n_values_per_frame;
15455     *stride_length = data->stride_length;
15456     n_frames_div = (*n_frames % *stride_length) ? *n_frames / *stride_length + 1:
15457                    *n_frames / *stride_length;
15458
15459     data_size = n_frames_div * size *
15460                 *n_values_per_frame;
15461
15462     temp = realloc(*values, data_size);
15463     if(!temp)
15464     {
15465         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15466                data_size, __FILE__, __LINE__);
15467         free(*values);
15468         *values = 0;
15469         return(TNG_CRITICAL);
15470     }
15471
15472     *values = temp;
15473
15474     memcpy(*values, data->values, data_size);
15475
15476     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
15477
15478     return(TNG_SUCCESS);
15479 }
15480
15481 tng_function_status DECLSPECDLLEXPORT tng_data_interval_get
15482                 (tng_trajectory_t tng_data,
15483                  const int64_t block_id,
15484                  const int64_t start_frame_nr,
15485                  const int64_t end_frame_nr,
15486                  const char hash_mode,
15487                  union data_values ***values,
15488                  int64_t *n_values_per_frame,
15489                  char *type)
15490 {
15491     int64_t i, j, n_frames, file_pos, current_frame_pos, first_frame;
15492     int64_t block_index;
15493     int size;
15494     size_t len;
15495     tng_non_particle_data_t data;
15496     tng_trajectory_frame_set_t frame_set;
15497     tng_gen_block_t block;
15498     tng_function_status stat;
15499
15500     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15501     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
15502     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15503     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15504
15505     block_index = -1;
15506
15507     frame_set = &tng_data->current_trajectory_frame_set;
15508     first_frame = frame_set->first_frame;
15509
15510     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
15511     if(stat != TNG_SUCCESS)
15512     {
15513         return(stat);
15514     }
15515
15516
15517     /* Do not re-read the frame set. */
15518     if(first_frame != frame_set->first_frame ||
15519        frame_set->n_data_blocks <= 0)
15520     {
15521         tng_block_init(&block);
15522         file_pos = ftell(tng_data->input_file);
15523         /* Read all blocks until next frame set block */
15524         stat = tng_block_header_read(tng_data, block);
15525         while(file_pos < tng_data->input_file_len &&
15526             stat != TNG_CRITICAL &&
15527             block->id != TNG_TRAJECTORY_FRAME_SET &&
15528             block->id != -1)
15529         {
15530             stat = tng_block_read_next(tng_data, block,
15531                                     hash_mode);
15532             if(stat != TNG_CRITICAL)
15533             {
15534                 file_pos = ftell(tng_data->input_file);
15535                 if(file_pos < tng_data->input_file_len)
15536                 {
15537                     stat = tng_block_header_read(tng_data, block);
15538                 }
15539             }
15540         }
15541         tng_block_destroy(&block);
15542         if(stat == TNG_CRITICAL)
15543         {
15544             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15545                     file_pos, __FILE__, __LINE__);
15546             return(stat);
15547         }
15548     }
15549
15550
15551     /* See if there is a data block of this ID.
15552      * Start checking the last read frame set */
15553     for(i = 0; i < frame_set->n_data_blocks; i++)
15554     {
15555         data = &frame_set->tr_data[i];
15556         if(data->block_id == block_id)
15557         {
15558             block_index = i;
15559             break;
15560         }
15561     }
15562
15563     if(block_index < 0)
15564     {
15565         fprintf(stderr, "TNG library: Could not find non-particle data block with id %"PRId64". %s: %d\n",
15566                 block_id, __FILE__, __LINE__);
15567         return(TNG_FAILURE);
15568     }
15569
15570     n_frames = end_frame_nr - start_frame_nr + 1;
15571     *n_values_per_frame = data->n_values_per_frame;
15572     *type = data->datatype;
15573
15574     if(*values == 0)
15575     {
15576         if(tng_data_values_alloc(tng_data, values, n_frames,
15577                                  *n_values_per_frame,
15578                                  *type) != TNG_SUCCESS)
15579         {
15580             return(TNG_CRITICAL);
15581         }
15582     }
15583
15584     current_frame_pos = start_frame_nr - frame_set->first_frame;
15585     /* It's not very elegant to reuse so much of the code in the different case
15586      * statements, but it's unnecessarily slow to have the switch-case block
15587      * inside the for loops. */
15588     switch(*type)
15589     {
15590     case TNG_CHAR_DATA:
15591         for(i=0; i<n_frames; i++)
15592         {
15593             if(current_frame_pos == frame_set->n_frames)
15594             {
15595                 stat = tng_frame_set_read_next(tng_data, hash_mode);
15596                 if(stat != TNG_SUCCESS)
15597                 {
15598                     return(stat);
15599                 }
15600                 current_frame_pos = 0;
15601             }
15602             for(j = 0; j < *n_values_per_frame; j++)
15603             {
15604                 len = strlen(data->strings[current_frame_pos][j]) + 1;
15605                 (*values)[i][j].c = malloc(len);
15606                 strncpy((*values)[i][j].c, data->strings[current_frame_pos][j], len);
15607             }
15608             current_frame_pos++;
15609         }
15610         break;
15611     case TNG_INT_DATA:
15612         size = sizeof(int);
15613         for(i=0; i<n_frames; i++)
15614         {
15615             if(current_frame_pos == frame_set->n_frames)
15616             {
15617                 stat = tng_frame_set_read_next(tng_data, hash_mode);
15618                 if(stat != TNG_SUCCESS)
15619                 {
15620                     return(stat);
15621                 }
15622                 current_frame_pos = 0;
15623             }
15624             for(j = 0; j < *n_values_per_frame; j++)
15625             {
15626                 (*values)[i][j].i = *(int *)((char *)data->values + size *
15627                                             (current_frame_pos *
15628                                              (*n_values_per_frame) + j));
15629             }
15630             current_frame_pos++;
15631         }
15632         break;
15633     case TNG_FLOAT_DATA:
15634         size = sizeof(float);
15635         for(i=0; i<n_frames; i++)
15636         {
15637             if(current_frame_pos == frame_set->n_frames)
15638             {
15639                 stat = tng_frame_set_read_next(tng_data, hash_mode);
15640                 if(stat != TNG_SUCCESS)
15641                 {
15642                     return(stat);
15643                 }
15644                 current_frame_pos = 0;
15645             }
15646             for(j = 0; j < *n_values_per_frame; j++)
15647             {
15648                 (*values)[i][j].f = *(float *)((char *)data->values + size *
15649                                                (current_frame_pos *
15650                                                 (*n_values_per_frame) + j));
15651             }
15652             current_frame_pos++;
15653         }
15654         break;
15655     case TNG_DOUBLE_DATA:
15656     default:
15657         size = sizeof(double);
15658         for(i=0; i<n_frames; i++)
15659         {
15660             if(current_frame_pos == frame_set->n_frames)
15661             {
15662                 stat = tng_frame_set_read_next(tng_data, hash_mode);
15663                 if(stat != TNG_SUCCESS)
15664                 {
15665                     return(stat);
15666                 }
15667                 current_frame_pos = 0;
15668             }
15669             for(j = 0; j < *n_values_per_frame; j++)
15670             {
15671                 (*values)[i][j].d = *(double *)((char *)data->values + size *
15672                                                 (current_frame_pos *
15673                                                  (*n_values_per_frame) + j));
15674             }
15675             current_frame_pos++;
15676         }
15677     }
15678
15679     data->last_retrieved_frame = end_frame_nr;
15680
15681     return(TNG_SUCCESS);
15682 }
15683
15684 tng_function_status DECLSPECDLLEXPORT tng_data_vector_interval_get
15685                 (tng_trajectory_t tng_data,
15686                  const int64_t block_id,
15687                  const int64_t start_frame_nr,
15688                  const int64_t end_frame_nr,
15689                  const char hash_mode,
15690                  void **values,
15691                  int64_t *stride_length,
15692                  int64_t *n_values_per_frame,
15693                  char *type)
15694 {
15695     int64_t n_frames, tot_n_frames, n_frames_div, n_frames_div_2, first_frame;
15696     int64_t file_pos, current_frame_pos, data_size, frame_size;
15697     int64_t last_frame_pos;
15698     int size;
15699     tng_trajectory_frame_set_t frame_set;
15700     tng_non_particle_data_t np_data;
15701     tng_gen_block_t block;
15702     void *current_values = 0, *temp;
15703     tng_function_status stat;
15704
15705     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15706     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than the end_frame_nr.");
15707     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
15708     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15709     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15710
15711     frame_set = &tng_data->current_trajectory_frame_set;
15712     first_frame = frame_set->first_frame;
15713
15714     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
15715     if(stat != TNG_SUCCESS)
15716     {
15717         return(stat);
15718     }
15719
15720     /* Do not re-read the frame set and only need the requested block. */
15721     /* TODO: Test that blocks are read correctly now that not all of them are read at the same time. */
15722     stat = tng_data_find(tng_data, block_id, &np_data);
15723     if(first_frame != frame_set->first_frame ||
15724        stat != TNG_SUCCESS)
15725     {
15726         tng_block_init(&block);
15727         if(stat != TNG_SUCCESS)
15728         {
15729             fseek(tng_data->input_file,
15730                   (long)tng_data->current_trajectory_frame_set_input_file_pos,
15731                   SEEK_SET);
15732             stat = tng_block_header_read(tng_data, block);
15733             if(stat != TNG_SUCCESS)
15734             {
15735                 fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n",
15736                         __FILE__, __LINE__);
15737                 return(stat);
15738             }
15739
15740             fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
15741         }
15742         file_pos = ftell(tng_data->input_file);
15743         /* Read until next frame set block */
15744         stat = tng_block_header_read(tng_data, block);
15745         while(file_pos < tng_data->input_file_len &&
15746             stat != TNG_CRITICAL &&
15747             block->id != TNG_TRAJECTORY_FRAME_SET &&
15748             block->id != -1)
15749         {
15750             if(block->id == block_id)
15751             {
15752                 stat = tng_block_read_next(tng_data, block,
15753                                         hash_mode);
15754                 if(stat != TNG_CRITICAL)
15755                 {
15756                     file_pos = ftell(tng_data->input_file);
15757                     if(file_pos < tng_data->input_file_len)
15758                     {
15759                         stat = tng_block_header_read(tng_data, block);
15760                     }
15761                 }
15762             }
15763             else
15764             {
15765                 file_pos += block->block_contents_size + block->header_contents_size;
15766                 fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
15767                 if(file_pos < tng_data->input_file_len)
15768                 {
15769                     stat = tng_block_header_read(tng_data, block);
15770                 }
15771             }
15772         }
15773         tng_block_destroy(&block);
15774         if(stat == TNG_CRITICAL)
15775         {
15776             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15777                     file_pos, __FILE__, __LINE__);
15778             return(stat);
15779         }
15780     }
15781
15782     stat = tng_data_find(tng_data, block_id, &np_data);
15783     if(stat != TNG_SUCCESS)
15784     {
15785         return(stat);
15786     }
15787
15788     stat = tng_data_vector_get(tng_data, block_id, &current_values,
15789                                &n_frames, stride_length,
15790                                n_values_per_frame, type);
15791
15792     if(stat != TNG_SUCCESS)
15793     {
15794         if(current_values)
15795         {
15796             free(current_values);
15797         }
15798         return(stat);
15799     }
15800
15801     if(n_frames == 1 && n_frames < frame_set->n_frames)
15802     {
15803         tot_n_frames = 1;
15804     }
15805     else
15806     {
15807         tot_n_frames = end_frame_nr - start_frame_nr + 1;
15808     }
15809
15810     switch(*type)
15811     {
15812     case TNG_CHAR_DATA:
15813         return(TNG_FAILURE);
15814     case TNG_INT_DATA:
15815         size = sizeof(int64_t);
15816         break;
15817     case TNG_FLOAT_DATA:
15818         size = sizeof(float);
15819         break;
15820     case TNG_DOUBLE_DATA:
15821     default:
15822         size = sizeof(double);
15823     }
15824
15825     n_frames_div = (tot_n_frames % *stride_length) ?
15826                  tot_n_frames / *stride_length + 1:
15827                  tot_n_frames / *stride_length;
15828     data_size = n_frames_div * size * (*n_values_per_frame);
15829
15830 /*     fprintf(stderr, "TNG library: size: %d, n_frames_div: %"PRId64", data_size: %"PRId64"\n",
15831               size, n_frames_div, data_size);
15832 */
15833     temp = realloc(*values, data_size);
15834     if(!temp)
15835     {
15836         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15837                data_size, __FILE__, __LINE__);
15838         free(*values);
15839         *values = 0;
15840         return(TNG_CRITICAL);
15841     }
15842
15843     *values = temp;
15844
15845     if( n_frames == 1 && n_frames < frame_set->n_frames)
15846     {
15847         memcpy(*values, current_values, size * (*n_values_per_frame));
15848     }
15849     else
15850     {
15851         current_frame_pos = start_frame_nr - frame_set->first_frame;
15852
15853         frame_size = size * (*n_values_per_frame);
15854
15855         last_frame_pos = tng_min_i64(n_frames,
15856                                      end_frame_nr - start_frame_nr);
15857
15858         n_frames_div = current_frame_pos / *stride_length;
15859         n_frames_div_2 = (last_frame_pos % *stride_length) ?
15860                        last_frame_pos / *stride_length + 1:
15861                        last_frame_pos / *stride_length;
15862         n_frames_div_2 = tng_max_i64(1, n_frames_div_2);
15863
15864         memcpy(*values, (char *)current_values + n_frames_div * frame_size,
15865                n_frames_div_2 * frame_size);
15866
15867         current_frame_pos += n_frames - current_frame_pos;
15868
15869         while(current_frame_pos <= end_frame_nr - start_frame_nr)
15870         {
15871             stat = tng_frame_set_read_next(tng_data, hash_mode);
15872             if(stat != TNG_SUCCESS)
15873             {
15874                 if(current_values)
15875                 {
15876                     free(current_values);
15877                 }
15878                 free(*values);
15879                 *values = 0;
15880                 return(stat);
15881             }
15882
15883             stat = tng_data_vector_get(tng_data, block_id, &current_values,
15884                                     &n_frames, stride_length,
15885                                     n_values_per_frame, type);
15886
15887             if(stat != TNG_SUCCESS)
15888             {
15889                 if(current_values)
15890                 {
15891                     free(current_values);
15892                 }
15893                 free(*values);
15894                 *values = 0;
15895                 return(stat);
15896             }
15897
15898             last_frame_pos = tng_min_i64(n_frames,
15899                                          end_frame_nr - current_frame_pos);
15900
15901             n_frames_div = current_frame_pos / *stride_length;
15902             n_frames_div_2 = (last_frame_pos % *stride_length) ?
15903                            last_frame_pos / *stride_length + 1:
15904                            last_frame_pos / *stride_length;
15905             n_frames_div_2 = tng_max_i64(1, n_frames_div_2);
15906
15907             memcpy(((char *)*values) + n_frames_div * frame_size,
15908                    current_values,
15909                    n_frames_div_2 * frame_size);
15910
15911             current_frame_pos += n_frames;
15912         }
15913     }
15914
15915     if(current_values)
15916     {
15917         free(current_values);
15918     }
15919
15920     np_data->last_retrieved_frame = end_frame_nr;
15921
15922     return(TNG_SUCCESS);
15923 }
15924
15925 tng_function_status DECLSPECDLLEXPORT tng_particle_data_get
15926                 (tng_trajectory_t tng_data,
15927                  const int64_t block_id,
15928                  union data_values ****values,
15929                  int64_t *n_frames,
15930                  int64_t *n_particles,
15931                  int64_t *n_values_per_frame,
15932                  char *type)
15933 {
15934     int64_t i, j, k, mapping, file_pos, i_step, block_index;
15935     int size;
15936     size_t len;
15937     tng_particle_data_t data;
15938     tng_trajectory_frame_set_t frame_set;
15939     tng_gen_block_t block;
15940     char block_type_flag;
15941     tng_function_status stat;
15942
15943     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15944     TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
15945     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
15946     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15947     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15948
15949     frame_set = &tng_data->current_trajectory_frame_set;
15950
15951     block_index = -1;
15952     data = 0;
15953
15954     if(tng_particle_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
15955     {
15956         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
15957         {
15958             block_type_flag = TNG_TRAJECTORY_BLOCK;
15959         }
15960         else
15961         {
15962             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
15963         }
15964
15965         tng_block_init(&block);
15966         file_pos = ftell(tng_data->input_file);
15967         /* Read all blocks until next frame set block */
15968         stat = tng_block_header_read(tng_data, block);
15969         while(file_pos < tng_data->input_file_len &&
15970                 stat != TNG_CRITICAL &&
15971                 block->id != TNG_TRAJECTORY_FRAME_SET &&
15972                 block->id != -1)
15973         {
15974             /* Use hash by default */
15975             stat = tng_block_read_next(tng_data, block,
15976                                     TNG_USE_HASH);
15977             if(stat != TNG_CRITICAL)
15978             {
15979                 file_pos = ftell(tng_data->input_file);
15980                 if(file_pos < tng_data->input_file_len)
15981                 {
15982                     stat = tng_block_header_read(tng_data, block);
15983                 }
15984             }
15985         }
15986         tng_block_destroy(&block);
15987         if(stat == TNG_CRITICAL)
15988         {
15989             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15990                     file_pos, __FILE__, __LINE__);
15991             return(stat);
15992         }
15993
15994         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
15995         {
15996             data = &frame_set->tr_particle_data[i];
15997             if(data->block_id == block_id)
15998             {
15999                 block_index = i;
16000                 block_type_flag = TNG_TRAJECTORY_BLOCK;
16001                 break;
16002             }
16003         }
16004         if(block_index < 0)
16005         {
16006             return(TNG_FAILURE);
16007         }
16008     }
16009     else
16010     {
16011         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
16012         {
16013             block_type_flag = TNG_TRAJECTORY_BLOCK;
16014         }
16015         else
16016         {
16017             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
16018         }
16019     }
16020
16021     if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
16022        tng_data->var_num_atoms_flag)
16023     {
16024         *n_particles = frame_set->n_particles;
16025     }
16026     else
16027     {
16028         *n_particles = tng_data->n_particles;
16029     }
16030
16031     *n_frames = tng_max_i64(1, data->n_frames);
16032     *n_values_per_frame = data->n_values_per_frame;
16033     *type = data->datatype;
16034
16035     if(*values == 0)
16036     {
16037         if(tng_particle_data_values_alloc(tng_data, values, *n_frames,
16038                                          *n_particles, *n_values_per_frame,
16039                                          *type)
16040             != TNG_SUCCESS)
16041         {
16042             return(TNG_CRITICAL);
16043         }
16044     }
16045
16046     /* It's not very elegant to reuse so much of the code in the different case
16047      * statements, but it's unnecessarily slow to have the switch-case block
16048      * inside the for loops. */
16049     switch(*type)
16050     {
16051     case TNG_CHAR_DATA:
16052         for(i = 0; i < *n_frames; i++)
16053         {
16054             for(j = 0; j < *n_particles; j++)
16055             {
16056                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16057                 for(k = 0; k < *n_values_per_frame; k++)
16058                 {
16059                     len = strlen(data->strings[i][j][k]) + 1;
16060                     (*values)[i][mapping][k].c = malloc(len);
16061                     strncpy((*values)[i][mapping][k].c,
16062                             data->strings[i][j][k], len);
16063                 }
16064             }
16065         }
16066         break;
16067     case TNG_INT_DATA:
16068         size = sizeof(int);
16069         i_step = (*n_particles) * (*n_values_per_frame);
16070         for(i = 0; i < *n_frames; i++)
16071         {
16072             for(j = 0; j < *n_particles; j++)
16073             {
16074                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16075                 for(k = 0; k < *n_values_per_frame; k++)
16076                 {
16077                     (*values)[i][mapping][k].i = *(int *)
16078                                                  ((char *)data->values + size *
16079                                                  (i * i_step + j *
16080                                                   (*n_values_per_frame) + k));
16081                 }
16082             }
16083         }
16084         break;
16085     case TNG_FLOAT_DATA:
16086         size = sizeof(float);
16087         i_step = (*n_particles) * (*n_values_per_frame);
16088         for(i = 0; i < *n_frames; i++)
16089         {
16090             for(j = 0; j < *n_particles; j++)
16091             {
16092                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16093                 for(k = 0; k < *n_values_per_frame; k++)
16094                 {
16095                     (*values)[i][mapping][k].f = *(float *)
16096                                                  ((char *)data->values + size *
16097                                                  (i * i_step + j *
16098                                                   (*n_values_per_frame) + k));
16099                 }
16100             }
16101         }
16102         break;
16103     case TNG_DOUBLE_DATA:
16104     default:
16105         size = sizeof(double);
16106         i_step = (*n_particles) * (*n_values_per_frame);
16107         for(i = 0; i < *n_frames; i++)
16108         {
16109             for(j = 0; j < *n_particles; j++)
16110             {
16111                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16112                 for(k = 0; k < *n_values_per_frame; k++)
16113                 {
16114                     (*values)[i][mapping][k].d = *(double *)
16115                                                  ((char *)data->values + size *
16116                                                  (i * i_step + j *
16117                                                   (*n_values_per_frame) + k));
16118                 }
16119             }
16120         }
16121     }
16122
16123     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
16124
16125     return(TNG_SUCCESS);
16126 }
16127
16128 tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_get
16129                 (tng_trajectory_t tng_data,
16130                  const int64_t block_id,
16131                  void **values,
16132                  int64_t *n_frames,
16133                  int64_t *stride_length,
16134                  int64_t *n_particles,
16135                  int64_t *n_values_per_frame,
16136                  char *type)
16137 {
16138     int64_t i, j, mapping, file_pos, i_step, data_size, n_frames_div;
16139     int64_t block_index;
16140     int size;
16141     tng_particle_data_t data;
16142     tng_trajectory_frame_set_t frame_set;
16143     tng_gen_block_t block;
16144     void *temp;
16145     char block_type_flag;
16146     tng_function_status stat;
16147
16148     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16149     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
16150     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
16151     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
16152     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
16153
16154     frame_set = &tng_data->current_trajectory_frame_set;
16155
16156     block_index = -1;
16157     data = 0;
16158
16159     if(tng_particle_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
16160     {
16161         tng_block_init(&block);
16162         file_pos = ftell(tng_data->input_file);
16163         /* Read all blocks until next frame set block */
16164         stat = tng_block_header_read(tng_data, block);
16165         while(file_pos < tng_data->input_file_len &&
16166                 stat != TNG_CRITICAL &&
16167                 block->id != TNG_TRAJECTORY_FRAME_SET &&
16168                 block->id != -1)
16169         {
16170             /* Use hash by default */
16171             stat = tng_block_read_next(tng_data, block,
16172                                     TNG_USE_HASH);
16173             if(stat != TNG_CRITICAL)
16174             {
16175                 file_pos = ftell(tng_data->input_file);
16176                 if(file_pos < tng_data->input_file_len)
16177                 {
16178                     stat = tng_block_header_read(tng_data, block);
16179                 }
16180             }
16181         }
16182         tng_block_destroy(&block);
16183         if(stat == TNG_CRITICAL)
16184         {
16185             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
16186                     file_pos, __FILE__, __LINE__);
16187             return(stat);
16188         }
16189
16190         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
16191         {
16192             data = &frame_set->tr_particle_data[i];
16193             if(data->block_id == block_id)
16194             {
16195                 block_index = i;
16196                 break;
16197             }
16198         }
16199         if(block_index < 0)
16200         {
16201             return(TNG_FAILURE);
16202         }
16203     }
16204
16205     if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
16206     {
16207         block_type_flag = TNG_TRAJECTORY_BLOCK;
16208     }
16209     else
16210     {
16211         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
16212     }
16213
16214    if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
16215       tng_data->var_num_atoms_flag)
16216     {
16217         *n_particles = frame_set->n_particles;
16218     }
16219     else
16220     {
16221         *n_particles = tng_data->n_particles;
16222     }
16223
16224     *type = data->datatype;
16225
16226     switch(*type)
16227     {
16228     case TNG_CHAR_DATA:
16229         return(TNG_FAILURE);
16230     case TNG_INT_DATA:
16231         size = sizeof(int64_t);
16232         break;
16233     case TNG_FLOAT_DATA:
16234         size = sizeof(float);
16235         break;
16236     case TNG_DOUBLE_DATA:
16237     default:
16238         size = sizeof(double);
16239     }
16240
16241     *n_frames = tng_max_i64(1, data->n_frames);
16242     *n_values_per_frame = data->n_values_per_frame;
16243     *stride_length = data->stride_length;
16244
16245     n_frames_div = (*n_frames % *stride_length) ?
16246                    *n_frames / *stride_length + 1:
16247                    *n_frames / *stride_length;
16248
16249     data_size = n_frames_div * size * (*n_particles) *
16250                 (*n_values_per_frame);
16251
16252     temp = realloc(*values, data_size);
16253     if(!temp)
16254     {
16255         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
16256                data_size, __FILE__, __LINE__);
16257         free(*values);
16258         *values = 0;
16259         return(TNG_CRITICAL);
16260     }
16261
16262     *values = temp;
16263
16264     if(frame_set->n_mapping_blocks <= 0)
16265     {
16266         memcpy(*values, data->values, data_size);
16267     }
16268     else
16269     {
16270         i_step = (*n_particles) * (*n_values_per_frame);
16271         for(i = 0; i < *n_frames; i++)
16272         {
16273             for(j = 0; j < *n_particles; j++)
16274             {
16275                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16276                 memcpy(((char *)*values) + size * (i * i_step + mapping *
16277                        (*n_values_per_frame)),
16278                        (char *)data->values + size *
16279                        (i * i_step + j * (*n_values_per_frame)),
16280                        size * (*n_values_per_frame));
16281             }
16282         }
16283     }
16284
16285     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
16286
16287     return(TNG_SUCCESS);
16288 }
16289
16290 tng_function_status DECLSPECDLLEXPORT tng_particle_data_interval_get
16291                 (tng_trajectory_t tng_data,
16292                  const int64_t block_id,
16293                  const int64_t start_frame_nr,
16294                  const int64_t end_frame_nr,
16295                  const char hash_mode,
16296                  union data_values ****values,
16297                  int64_t *n_particles,
16298                  int64_t *n_values_per_frame,
16299                  char *type)
16300 {
16301     int64_t i, j, k, mapping, n_frames, file_pos, current_frame_pos, i_step;
16302     int64_t first_frame, block_index;
16303     int size;
16304     size_t len;
16305     tng_particle_data_t data;
16306     tng_trajectory_frame_set_t frame_set;
16307     tng_gen_block_t block;
16308     char block_type_flag;
16309     tng_function_status stat;
16310
16311     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16312     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
16313     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
16314     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
16315     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
16316
16317     block_index = -1;
16318
16319     frame_set = &tng_data->current_trajectory_frame_set;
16320     first_frame = frame_set->first_frame;
16321
16322     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
16323     if(stat != TNG_SUCCESS)
16324     {
16325         return(stat);
16326     }
16327
16328     /* Do not re-read the frame set. */
16329     if(first_frame != frame_set->first_frame ||
16330        frame_set->n_particle_data_blocks <= 0)
16331     {
16332         tng_block_init(&block);
16333         file_pos = ftell(tng_data->input_file);
16334         /* Read all blocks until next frame set block */
16335         stat = tng_block_header_read(tng_data, block);
16336         while(file_pos < tng_data->input_file_len &&
16337                 stat != TNG_CRITICAL &&
16338                 block->id != TNG_TRAJECTORY_FRAME_SET &&
16339                 block->id != -1)
16340         {
16341             stat = tng_block_read_next(tng_data, block,
16342                                     hash_mode);
16343             if(stat != TNG_CRITICAL)
16344             {
16345                 file_pos = ftell(tng_data->input_file);
16346                 if(file_pos < tng_data->input_file_len)
16347                 {
16348                     stat = tng_block_header_read(tng_data, block);
16349                 }
16350             }
16351         }
16352         tng_block_destroy(&block);
16353         if(stat == TNG_CRITICAL)
16354         {
16355             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
16356                     file_pos, __FILE__, __LINE__);
16357             return(stat);
16358         }
16359     }
16360
16361     /* See if there is already a data block of this ID.
16362      * Start checking the last read frame set */
16363     for(i = frame_set->n_particle_data_blocks; i-- ;)
16364     {
16365         data = &frame_set->tr_particle_data[i];
16366         if(data->block_id == block_id)
16367         {
16368             block_index = i;
16369             block_type_flag = TNG_TRAJECTORY_BLOCK;
16370             break;
16371         }
16372     }
16373
16374     if(block_index < 0)
16375     {
16376         fprintf(stderr, "TNG library: Could not find particle data block with id %"PRId64". %s: %d\n",
16377                 block_id, __FILE__, __LINE__);
16378         return(TNG_FAILURE);
16379     }
16380
16381     if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
16382        tng_data->var_num_atoms_flag)
16383     {
16384         *n_particles = frame_set->n_particles;
16385     }
16386     else
16387     {
16388         *n_particles = tng_data->n_particles;
16389     }
16390
16391     n_frames = end_frame_nr - start_frame_nr + 1;
16392     *n_values_per_frame = data->n_values_per_frame;
16393     *type = data->datatype;
16394
16395     if(*values == 0)
16396     {
16397         if(tng_particle_data_values_alloc(tng_data, values, n_frames,
16398                                          *n_particles, *n_values_per_frame,
16399                                          *type)
16400             != TNG_SUCCESS)
16401         {
16402             return(TNG_CRITICAL);
16403         }
16404     }
16405
16406     current_frame_pos = start_frame_nr - frame_set->first_frame;
16407     /* It's not very elegant to reuse so much of the code in the different case
16408      * statements, but it's unnecessarily slow to have the switch-case block
16409      * inside the for loops. */
16410     switch(*type)
16411     {
16412     case TNG_CHAR_DATA:
16413         for(i=0; i<n_frames; i++)
16414         {
16415             if(current_frame_pos == frame_set->n_frames)
16416             {
16417                 stat = tng_frame_set_read_next(tng_data, hash_mode);
16418                 if(stat != TNG_SUCCESS)
16419                 {
16420                     return(stat);
16421                 }
16422                 current_frame_pos = 0;
16423             }
16424             for(j = 0; j < *n_particles; j++)
16425             {
16426                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16427                 for(k = 0; k < *n_values_per_frame; k++)
16428                 {
16429                     len = strlen(data->strings[current_frame_pos][j][k]) + 1;
16430                     (*values)[i][mapping][k].c = malloc(len);
16431                     strncpy((*values)[i][mapping][k].c, data->strings[current_frame_pos][j][k], len);
16432                 }
16433             }
16434             current_frame_pos++;
16435         }
16436         break;
16437     case TNG_INT_DATA:
16438         size = sizeof(int);
16439         i_step = (*n_particles) * (*n_values_per_frame);
16440         for(i=0; i<n_frames; i++)
16441         {
16442             if(current_frame_pos == frame_set->n_frames)
16443             {
16444                 stat = tng_frame_set_read_next(tng_data, hash_mode);
16445                 if(stat != TNG_SUCCESS)
16446                 {
16447                     return(stat);
16448                 }
16449                 current_frame_pos = 0;
16450             }
16451             for(j = 0; j < *n_particles; j++)
16452             {
16453                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16454                 for(k = 0; k < *n_values_per_frame; k++)
16455                 {
16456                     (*values)[i][mapping][k].i = *(int *)
16457                                                  ((char *)data->values + size *
16458                                                   (current_frame_pos *
16459                                                    i_step + j *
16460                                                    (*n_values_per_frame) + k));
16461                 }
16462             }
16463             current_frame_pos++;
16464         }
16465         break;
16466     case TNG_FLOAT_DATA:
16467         size = sizeof(float);
16468         i_step = (*n_particles) * (*n_values_per_frame);
16469         for(i=0; i<n_frames; i++)
16470         {
16471             if(current_frame_pos == frame_set->n_frames)
16472             {
16473                 stat = tng_frame_set_read_next(tng_data, hash_mode);
16474                 if(stat != TNG_SUCCESS)
16475                 {
16476                     return(stat);
16477                 }
16478                 current_frame_pos = 0;
16479             }
16480             for(j=0; j<*n_particles; j++)
16481             {
16482                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16483                 for(k=0; k<*n_values_per_frame; k++)
16484                 {
16485                     (*values)[i][mapping][k].f = *(float *)
16486                                                  ((char *)data->values + size *
16487                                                   (current_frame_pos *
16488                                                    i_step + j *
16489                                                    (*n_values_per_frame) + k));
16490                 }
16491             }
16492             current_frame_pos++;
16493         }
16494         break;
16495     case TNG_DOUBLE_DATA:
16496     default:
16497         size = sizeof(double);
16498         i_step = (*n_particles) * (*n_values_per_frame);
16499         for(i=0; i<n_frames; i++)
16500         {
16501             if(current_frame_pos == frame_set->n_frames)
16502             {
16503                 stat = tng_frame_set_read_next(tng_data, hash_mode);
16504                 if(stat != TNG_SUCCESS)
16505                 {
16506                     return(stat);
16507                 }
16508                 current_frame_pos = 0;
16509             }
16510             for(j=0; j<*n_particles; j++)
16511             {
16512                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16513                 for(k=0; k<*n_values_per_frame; k++)
16514                 {
16515                     (*values)[i][mapping][k].d = *(double *)
16516                                                  ((char *)data->values + size *
16517                                                   (current_frame_pos *
16518                                                    i_step + j *
16519                                                    (*n_values_per_frame) + k));
16520                 }
16521             }
16522             current_frame_pos++;
16523         }
16524     }
16525
16526     data->last_retrieved_frame = end_frame_nr;
16527
16528     return(TNG_SUCCESS);
16529 }
16530
16531 tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_interval_get
16532                 (tng_trajectory_t tng_data,
16533                  const int64_t block_id,
16534                  const int64_t start_frame_nr,
16535                  const int64_t end_frame_nr,
16536                  const char hash_mode,
16537                  void **values,
16538                  int64_t *n_particles,
16539                  int64_t *stride_length,
16540                  int64_t *n_values_per_frame,
16541                  char *type)
16542 {
16543     int64_t n_frames, tot_n_frames, n_frames_div, n_frames_div_2, first_frame;
16544     int64_t file_pos, current_frame_pos, last_frame_pos, data_size, frame_size;
16545     int size;
16546     tng_trajectory_frame_set_t frame_set;
16547     tng_particle_data_t p_data;
16548     tng_gen_block_t block;
16549     void *current_values = 0, *temp;
16550     tng_function_status stat;
16551
16552     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16553     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
16554     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
16555     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
16556     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
16557     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
16558
16559     frame_set = &tng_data->current_trajectory_frame_set;
16560     first_frame = frame_set->first_frame;
16561
16562     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
16563     if(stat != TNG_SUCCESS)
16564     {
16565         return(stat);
16566     }
16567
16568     /* Do not re-read the frame set and only need the requested block + particle mapping blocks. */
16569     /* TODO: Test that blocks are read correctly now that now all of them are read at the same time. */
16570     stat = tng_particle_data_find(tng_data, block_id, &p_data);
16571     if(first_frame != frame_set->first_frame ||
16572        stat != TNG_SUCCESS)
16573     {
16574         tng_block_init(&block);
16575         if(stat != TNG_SUCCESS)
16576         {
16577             fseek(tng_data->input_file,
16578                   (long)tng_data->current_trajectory_frame_set_input_file_pos,
16579                   SEEK_SET);
16580             stat = tng_block_header_read(tng_data, block);
16581             if(stat != TNG_SUCCESS)
16582             {
16583                 fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n",
16584                         __FILE__, __LINE__);
16585                 return(stat);
16586             }
16587
16588             fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
16589         }
16590         file_pos = ftell(tng_data->input_file);
16591         /* Read until next frame set block */
16592         stat = tng_block_header_read(tng_data, block);
16593         while(file_pos < tng_data->input_file_len &&
16594             stat != TNG_CRITICAL &&
16595             block->id != TNG_TRAJECTORY_FRAME_SET &&
16596             block->id != -1)
16597         {
16598             if(block->id == block_id || block->id == TNG_PARTICLE_MAPPING)
16599             {
16600                 stat = tng_block_read_next(tng_data, block,
16601                                         hash_mode);
16602                 if(stat != TNG_CRITICAL)
16603                 {
16604                     file_pos = ftell(tng_data->input_file);
16605                     if(file_pos < tng_data->input_file_len)
16606                     {
16607                         stat = tng_block_header_read(tng_data, block);
16608                     }
16609                 }
16610             }
16611             else
16612             {
16613                 file_pos += block->block_contents_size + block->header_contents_size;
16614                 fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
16615                 if(file_pos < tng_data->input_file_len)
16616                 {
16617                     stat = tng_block_header_read(tng_data, block);
16618                 }
16619             }
16620         }
16621         tng_block_destroy(&block);
16622         if(stat == TNG_CRITICAL)
16623         {
16624             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
16625                     file_pos, __FILE__, __LINE__);
16626             return(stat);
16627         }
16628     }
16629     stat = tng_particle_data_find(tng_data, block_id, &p_data);
16630     if(stat != TNG_SUCCESS)
16631     {
16632         return(stat);
16633     }
16634
16635     stat = tng_particle_data_vector_get(tng_data, block_id, &current_values,
16636                                         &n_frames, stride_length, n_particles,
16637                                         n_values_per_frame, type);
16638
16639     if(stat != TNG_SUCCESS || *n_particles == 0)
16640     {
16641         if(current_values)
16642         {
16643             free(current_values);
16644         }
16645         return(stat);
16646     }
16647
16648     if(n_frames == 1 && n_frames < frame_set->n_frames)
16649     {
16650         tot_n_frames = 1;
16651     }
16652     else
16653     {
16654         tot_n_frames = end_frame_nr - start_frame_nr + 1;
16655     }
16656
16657     switch(*type)
16658     {
16659     case TNG_CHAR_DATA:
16660         return(TNG_FAILURE);
16661     case TNG_INT_DATA:
16662         size = sizeof(int64_t);
16663         break;
16664     case TNG_FLOAT_DATA:
16665         size = sizeof(float);
16666         break;
16667     case TNG_DOUBLE_DATA:
16668     default:
16669         size = sizeof(double);
16670     }
16671
16672     n_frames_div = (tot_n_frames % *stride_length) ?
16673                  tot_n_frames / *stride_length + 1:
16674                  tot_n_frames / *stride_length;
16675
16676     data_size = n_frames_div * size * (*n_particles) *
16677                 (*n_values_per_frame);
16678
16679     temp = realloc(*values, data_size);
16680     if(!temp)
16681     {
16682         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
16683                data_size, __FILE__, __LINE__);
16684         free(*values);
16685         *values = 0;
16686         return(TNG_CRITICAL);
16687     }
16688
16689     *values = temp;
16690
16691     if( n_frames == 1 && n_frames < frame_set->n_frames)
16692     {
16693         memcpy(*values, current_values, size * (*n_particles) *
16694                (*n_values_per_frame));
16695     }
16696     else
16697     {
16698         current_frame_pos = start_frame_nr - frame_set->first_frame;
16699
16700         frame_size = size * (*n_particles) * (*n_values_per_frame);
16701
16702         last_frame_pos = tng_min_i64(n_frames,
16703                                      end_frame_nr - start_frame_nr);
16704
16705         n_frames_div = current_frame_pos / *stride_length;
16706         n_frames_div_2 = (last_frame_pos % *stride_length) ?
16707                        last_frame_pos / *stride_length + 1:
16708                        last_frame_pos / *stride_length;
16709         n_frames_div_2 = tng_max_i64(1, n_frames_div_2 + 1);
16710
16711         memcpy(*values, (char *)current_values + n_frames_div * frame_size,
16712                n_frames_div_2 * frame_size);
16713
16714         current_frame_pos += n_frames - current_frame_pos;
16715
16716         while(current_frame_pos <= end_frame_nr - start_frame_nr)
16717         {
16718             stat = tng_frame_set_read_next(tng_data, hash_mode);
16719             if(stat != TNG_SUCCESS)
16720             {
16721                 if(current_values)
16722                 {
16723                     free(current_values);
16724                 }
16725                 free(*values);
16726                 *values = 0;
16727                 return(stat);
16728             }
16729
16730             stat = tng_particle_data_vector_get(tng_data, block_id, &current_values,
16731                                                 &n_frames, stride_length, n_particles,
16732                                                 n_values_per_frame, type);
16733
16734             if(stat != TNG_SUCCESS)
16735             {
16736                 if(current_values)
16737                 {
16738                     free(current_values);
16739                 }
16740                 free(*values);
16741                 *values = 0;
16742                 return(stat);
16743             }
16744
16745             last_frame_pos = tng_min_i64(n_frames,
16746                                          end_frame_nr - current_frame_pos);
16747
16748             n_frames_div = current_frame_pos / *stride_length;
16749             n_frames_div_2 = (last_frame_pos % *stride_length) ?
16750                            last_frame_pos / *stride_length + 1:
16751                            last_frame_pos / *stride_length;
16752             n_frames_div_2 = tng_max_i64(1, n_frames_div_2);
16753
16754             memcpy(((char *)*values) + n_frames_div * frame_size,
16755                    current_values,
16756                    n_frames_div_2 * frame_size);
16757
16758             current_frame_pos += n_frames;
16759         }
16760     }
16761
16762     if(current_values)
16763     {
16764         free(current_values);
16765     }
16766
16767     p_data->last_retrieved_frame = end_frame_nr;
16768
16769     return(TNG_SUCCESS);
16770 }
16771
16772 tng_function_status DECLSPECDLLEXPORT tng_data_get_stride_length
16773                 (const tng_trajectory_t tng_data,
16774                  const int64_t block_id,
16775                  int64_t frame,
16776                  int64_t *stride_length)
16777 {
16778     tng_function_status stat;
16779     tng_non_particle_data_t np_data;
16780     tng_particle_data_t p_data;
16781     long orig_file_pos, file_pos;
16782     int is_particle_data;
16783
16784     if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
16785     {
16786         frame = 0;
16787     }
16788
16789     if(frame >= 0)
16790     {
16791         stat = tng_frame_set_of_frame_find(tng_data, frame);
16792         if(stat != TNG_SUCCESS)
16793         {
16794             return(stat);
16795         }
16796     }
16797     orig_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
16798     stat = tng_data_find(tng_data, block_id, &np_data);
16799     if(stat != TNG_SUCCESS)
16800     {
16801         stat = tng_particle_data_find(tng_data, block_id, &p_data);
16802         if(stat != TNG_SUCCESS)
16803         {
16804             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16805             /* If no specific frame was required read until this data block is found */
16806             if(frame < 0)
16807             {
16808                 file_pos = ftell(tng_data->input_file);
16809                 while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
16810                 {
16811                     stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16812                     file_pos = ftell(tng_data->input_file);
16813                 }
16814             }
16815             if(stat != TNG_SUCCESS)
16816             {
16817                 tng_reread_frame_set_at_file_pos(tng_data, orig_file_pos);
16818
16819                 return(stat);
16820             }
16821             stat = tng_data_find(tng_data, block_id, &np_data);
16822             if(stat != TNG_SUCCESS)
16823             {
16824                 stat = tng_particle_data_find(tng_data, block_id, &p_data);
16825                 if(stat != TNG_SUCCESS)
16826                 {
16827                     tng_reread_frame_set_at_file_pos(tng_data, orig_file_pos);
16828
16829                     return(stat);
16830                 }
16831                 else
16832                 {
16833                     is_particle_data = 1;
16834                 }
16835             }
16836             else
16837             {
16838                 is_particle_data = 0;
16839             }
16840         }
16841         else
16842         {
16843             is_particle_data = 1;
16844         }
16845     }
16846     else
16847     {
16848         is_particle_data = 0;
16849     }
16850     if(is_particle_data)
16851     {
16852         *stride_length = p_data->stride_length;
16853     }
16854     else
16855     {
16856         *stride_length = np_data->stride_length;
16857     }
16858     tng_reread_frame_set_at_file_pos(tng_data, orig_file_pos);
16859
16860     return(TNG_SUCCESS);
16861 }
16862
16863 tng_function_status DECLSPECDLLEXPORT tng_time_get_str
16864                 (const tng_trajectory_t tng_data,
16865                  char *time)
16866 {
16867     struct tm *time_data;
16868     time_t secs;
16869
16870     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16871     TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
16872
16873     secs = tng_data->time;
16874
16875     time_data = localtime(&secs); /* Returns a statically allocated variable. */
16876     TNG_SNPRINTF(time, TNG_MAX_DATE_STR_LEN,
16877              "%4d-%02d-%02d %02d:%02d:%02d",
16878              time_data->tm_year+1900, time_data->tm_mon+1, time_data->tm_mday,
16879              time_data->tm_hour, time_data->tm_min, time_data->tm_sec);
16880
16881     return(TNG_SUCCESS);
16882 }
16883
16884
16885 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_open
16886                 (const char *filename,
16887                  const char mode,
16888                  tng_trajectory_t *tng_data_p)
16889 {
16890     tng_function_status stat;
16891
16892     TNG_ASSERT(filename, "TNG library: filename must not be a NULL pointer.");
16893
16894     if(mode != 'r' && mode != 'w' && mode != 'a')
16895     {
16896         return(TNG_FAILURE);
16897     }
16898
16899     if(tng_trajectory_init(tng_data_p) != TNG_SUCCESS)
16900     {
16901         tng_trajectory_destroy(tng_data_p);
16902         return(TNG_CRITICAL);
16903     }
16904
16905     if(mode == 'r' || mode == 'a')
16906     {
16907         tng_input_file_set(*tng_data_p, filename);
16908
16909         /* Read the file headers */
16910         tng_file_headers_read(*tng_data_p, TNG_USE_HASH);
16911
16912         stat = tng_num_frame_sets_get(*tng_data_p, &(*tng_data_p)->n_trajectory_frame_sets);
16913
16914         if(stat != TNG_SUCCESS)
16915         {
16916             return(stat);
16917         }
16918     }
16919
16920     if(mode == 'w')
16921     {
16922         tng_output_file_set(*tng_data_p, filename);
16923     }
16924     else if(mode == 'a')
16925     {
16926         if((*tng_data_p)->output_file)
16927         {
16928             fclose((*tng_data_p)->output_file);
16929         }
16930         (*tng_data_p)->output_file = (*tng_data_p)->input_file;
16931         fseek((*tng_data_p)->input_file,
16932                 (long)(*tng_data_p)->last_trajectory_frame_set_input_file_pos,
16933                 SEEK_SET);
16934
16935         stat = tng_frame_set_read(*tng_data_p, TNG_USE_HASH);
16936         if(stat != TNG_SUCCESS)
16937         {
16938             fprintf(stderr, "TNG library: Cannot read frame set and related blocks. %s: %d\n",
16939                    __FILE__, __LINE__);
16940         }
16941         (*tng_data_p)->output_file = 0;
16942
16943         (*tng_data_p)->first_trajectory_frame_set_output_file_pos =
16944         (*tng_data_p)->first_trajectory_frame_set_input_file_pos;
16945         (*tng_data_p)->last_trajectory_frame_set_output_file_pos =
16946         (*tng_data_p)->last_trajectory_frame_set_input_file_pos;
16947         (*tng_data_p)->current_trajectory_frame_set_output_file_pos =
16948         (*tng_data_p)->current_trajectory_frame_set_input_file_pos;
16949         if((*tng_data_p)->input_file)
16950         {
16951             fclose((*tng_data_p)->input_file);
16952             (*tng_data_p)->input_file = 0;
16953         }
16954         if((*tng_data_p)->input_file_path)
16955         {
16956             free((*tng_data_p)->input_file_path);
16957             (*tng_data_p)->input_file_path = 0;
16958         }
16959         tng_output_append_file_set(*tng_data_p, filename);
16960
16961         fseek((*tng_data_p)->output_file, 0, SEEK_END);
16962     }
16963
16964     return(TNG_SUCCESS);
16965 }
16966
16967 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_close
16968                 (tng_trajectory_t *tng_data_p)
16969 {
16970     tng_trajectory_frame_set_t frame_set;
16971
16972     if(tng_data_p == 0)
16973     {
16974         fprintf(stderr, "TNG library: Empty pointer to trajectory when attempting to close. %s: %d\n",
16975                __FILE__, __LINE__);
16976         return(TNG_FAILURE);
16977     }
16978
16979     if(*tng_data_p == 0)
16980     {
16981         return(TNG_SUCCESS);
16982     }
16983
16984     frame_set = &(*tng_data_p)->current_trajectory_frame_set;
16985
16986     if(frame_set->n_unwritten_frames > 0)
16987     {
16988         frame_set->n_frames = frame_set->n_unwritten_frames;
16989         tng_frame_set_write(*tng_data_p, TNG_USE_HASH);
16990     }
16991
16992     return(tng_trajectory_destroy(tng_data_p));
16993 }
16994
16995 tng_function_status DECLSPECDLLEXPORT tng_util_time_of_frame_get
16996                 (tng_trajectory_t tng_data,
16997                  const int64_t frame_nr,
16998                  double *time)
16999 {
17000     int64_t first_frame;
17001     tng_trajectory_frame_set_t frame_set;
17002     tng_function_status stat;
17003
17004     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17005     TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
17006
17007     stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
17008     if(stat != TNG_SUCCESS)
17009     {
17010         fprintf(stderr, "TNG library: Cannot find frame nr %"PRId64". %s: %d\n",
17011                frame_nr, __FILE__, __LINE__);
17012         return(stat);
17013     }
17014
17015     frame_set = &tng_data->current_trajectory_frame_set;
17016     first_frame = frame_set->first_frame;
17017
17018     if(tng_data->time_per_frame <= 0)
17019     {
17020         return(TNG_FAILURE);
17021     }
17022
17023     *time = frame_set->first_frame_time + (tng_data->time_per_frame * (frame_nr - first_frame));
17024
17025     return(TNG_SUCCESS);
17026 }
17027
17028 /*
17029 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_molecules_get
17030                 (tng_trajectory_t tng_data,
17031                  int64_t *n_mols,
17032                  int64_t **molecule_cnt_list,
17033                  tng_molecule_t *mols)
17034 {
17035     tng_trajectory_frame_set_t frame_set;
17036
17037     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17038     TNG_ASSERT(n_mols, "TNG library: n_mols must not be a NULL pointer.");
17039
17040     *n_mols = tng_data->n_molecules;
17041
17042     frame_set = &tng_data->current_trajectory_frame_set;
17043     if(tng_data->var_num_atoms_flag && frame_set && frame_set->molecule_cnt_list)
17044     {
17045         *molecule_cnt_list = frame_set->molecule_cnt_list;
17046     }
17047     else
17048     {
17049         *molecule_cnt_list = tng_data->molecule_cnt_list;
17050     }
17051
17052     *mols = tng_data->molecules;
17053
17054     return(TNG_SUCCESS);
17055 }
17056 */
17057 /*
17058 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_molecule_add
17059                 (tng_trajectory_t tng_data,
17060                  const char *name,
17061                  const int64_t cnt,
17062                  tng_molecule_t *mol)
17063 {
17064     tng_function_status stat;
17065
17066     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
17067     TNG_ASSERT(cnt>=0, "TNG library: cnt must be >= 0");
17068
17069     stat = tng_molecule_add(tng_data, name, mol);
17070     if(stat != TNG_SUCCESS)
17071     {
17072         return(stat);
17073     }
17074     stat = tng_molecule_cnt_set(tng_data, *mol, cnt);
17075
17076     return(stat);
17077 }
17078 */
17079 tng_function_status DECLSPECDLLEXPORT tng_util_molecule_particles_get
17080                 (tng_trajectory_t tng_data,
17081                  const tng_molecule_t mol,
17082                  int64_t *n_particles,
17083                  char ***names,
17084                  char ***types,
17085                  char ***res_names,
17086                  int64_t **res_ids,
17087                  char ***chain_names,
17088                  int64_t **chain_ids)
17089 {
17090     tng_atom_t atom;
17091     tng_residue_t res;
17092     tng_chain_t chain;
17093     int64_t i;
17094     (void)tng_data;
17095
17096     *n_particles = mol->n_atoms;
17097
17098     *names = malloc(sizeof(char *) * *n_particles);
17099     *types = malloc(sizeof(char *) * *n_particles);
17100     *res_names = malloc(sizeof(char *) * *n_particles);
17101     *chain_names = malloc(sizeof(char *) * *n_particles);
17102     *res_ids = malloc(sizeof(int64_t) * *n_particles);
17103     *chain_ids = malloc(sizeof(int64_t) * *n_particles);
17104
17105     for(i = 0; i < *n_particles; i++)
17106     {
17107         atom = &mol->atoms[i];
17108         res = atom->residue;
17109         chain = res->chain;
17110         (*names)[i] = malloc(strlen(atom->name));
17111         strcpy(*names[i], atom->name);
17112         (*types)[i] = malloc(strlen(atom->atom_type));
17113         strcpy(*types[i], atom->atom_type);
17114         (*res_names)[i] = malloc(strlen(res->name));
17115         strcpy(*res_names[i], res->name);
17116         (*chain_names)[i] = malloc(strlen(chain->name));
17117         strcpy(*chain_names[i], chain->name);
17118         (*res_ids)[i] = res->id;
17119         (*chain_ids)[i] = chain->id;
17120     }
17121
17122     return(TNG_SUCCESS);
17123 }
17124
17125 tng_function_status DECLSPECDLLEXPORT tng_util_molecule_particles_set
17126                 (tng_trajectory_t tng_data,
17127                  tng_molecule_t mol,
17128                  const int64_t n_particles,
17129                  const char **names,
17130                  const char **types,
17131                  const char **res_names,
17132                  const int64_t *res_ids,
17133                  const char **chain_names,
17134                  const int64_t *chain_ids)
17135 {
17136     int64_t i;
17137     tng_chain_t chain;
17138     tng_residue_t residue;
17139     tng_atom_t atom;
17140     tng_function_status stat;
17141
17142     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17143     TNG_ASSERT(names, "TNG library: names must not be a NULL pointer");
17144     TNG_ASSERT(types, "TNG library: types must not be a NULL pointer");
17145     TNG_ASSERT(res_names, "TNG library: res_names must not be a NULL pointer");
17146     TNG_ASSERT(res_ids, "TNG library: res_ids must not be a NULL pointer");
17147     TNG_ASSERT(chain_names, "TNG library: chain_names must not be a NULL pointer");
17148     TNG_ASSERT(chain_ids, "TNG library: chain_ids must not be a NULL pointer");
17149
17150     for(i = 0; i < n_particles; i++)
17151     {
17152         if(tng_molecule_chain_find(tng_data, mol, chain_names[i], chain_ids[i],
17153            &chain) == TNG_FAILURE)
17154         {
17155             stat = tng_molecule_chain_add(tng_data, mol, chain_names[i],
17156                                           &chain);
17157             if(stat != TNG_SUCCESS)
17158             {
17159                 return(stat);
17160             }
17161         }
17162         if(tng_chain_residue_find(tng_data, chain, res_names[i], res_ids[i],
17163            &residue) == TNG_FAILURE)
17164         {
17165             stat = tng_chain_residue_add(tng_data, chain, res_names[i],
17166                                          &residue);
17167             if(stat != TNG_SUCCESS)
17168             {
17169                 return(stat);
17170             }
17171         }
17172         stat = tng_residue_atom_add(tng_data, residue, names[i], types[i], &atom);
17173         if(stat != TNG_SUCCESS)
17174         {
17175             return(stat);
17176         }
17177     }
17178     return(TNG_SUCCESS);
17179 }
17180
17181 tng_function_status DECLSPECDLLEXPORT tng_util_pos_read
17182                 (tng_trajectory_t tng_data,
17183                  float **positions, int64_t *stride_length)
17184 {
17185     int64_t n_frames, n_particles, n_values_per_frame;
17186     char type;
17187     tng_function_status stat;
17188
17189     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17190     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
17191     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17192
17193     stat = tng_num_frames_get(tng_data, &n_frames);
17194     if(stat != TNG_SUCCESS)
17195     {
17196         return(stat);
17197     }
17198
17199     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_POSITIONS,
17200                                                  0, n_frames - 1, TNG_USE_HASH,
17201                                                  (void **)positions,
17202                                                  &n_particles,
17203                                                  stride_length,
17204                                                  &n_values_per_frame,
17205                                                  &type);
17206
17207     return(stat);
17208 }
17209
17210 tng_function_status DECLSPECDLLEXPORT tng_util_vel_read
17211                 (tng_trajectory_t tng_data,
17212                  float **velocities, int64_t *stride_length)
17213 {
17214     int64_t n_frames, n_particles, n_values_per_frame;
17215     char type;
17216     tng_function_status stat;
17217
17218     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17219     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
17220     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17221
17222     stat = tng_num_frames_get(tng_data, &n_frames);
17223     if(stat != TNG_SUCCESS)
17224     {
17225         return(stat);
17226     }
17227
17228     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_VELOCITIES,
17229                                                  0, n_frames - 1, TNG_USE_HASH,
17230                                                  (void **)velocities,
17231                                                  &n_particles,
17232                                                  stride_length,
17233                                                  &n_values_per_frame,
17234                                                  &type);
17235
17236     return(stat);
17237 }
17238
17239 tng_function_status DECLSPECDLLEXPORT tng_util_force_read
17240                 (tng_trajectory_t tng_data,
17241                  float **forces, int64_t *stride_length)
17242 {
17243     int64_t n_frames, n_particles, n_values_per_frame;
17244     char type;
17245     tng_function_status stat;
17246
17247     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17248     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
17249     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17250
17251     stat = tng_num_frames_get(tng_data, &n_frames);
17252     if(stat != TNG_SUCCESS)
17253     {
17254         return(stat);
17255     }
17256
17257     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_FORCES,
17258                                                  0, n_frames - 1, TNG_USE_HASH,
17259                                                  (void **)forces,
17260                                                  &n_particles,
17261                                                  stride_length,
17262                                                  &n_values_per_frame,
17263                                                  &type);
17264
17265     return(stat);
17266 }
17267
17268 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_read
17269                 (tng_trajectory_t tng_data,
17270                  float **box_shape,
17271                  int64_t *stride_length)
17272 {
17273     int64_t n_frames, n_values_per_frame;
17274     char type;
17275     tng_function_status stat;
17276
17277     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17278     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
17279     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17280
17281     stat = tng_num_frames_get(tng_data, &n_frames);
17282     if(stat != TNG_SUCCESS)
17283     {
17284         return(stat);
17285     }
17286
17287     stat = tng_data_vector_interval_get(tng_data, TNG_TRAJ_BOX_SHAPE,
17288                                         0, n_frames - 1, TNG_USE_HASH,
17289                                         (void **)box_shape,
17290                                         stride_length,
17291                                         &n_values_per_frame,
17292                                         &type);
17293
17294     return(stat);
17295 }
17296
17297 tng_function_status DECLSPECDLLEXPORT tng_util_particle_data_next_frame_read
17298                 (tng_trajectory_t tng_data,
17299                  const int64_t block_id,
17300                  void **values,
17301                  char *data_type,
17302                  int64_t *retrieved_frame_number,
17303                  double *retrieved_time)
17304 {
17305     tng_trajectory_frame_set_t frame_set;
17306     tng_particle_data_t data = 0;
17307     tng_function_status stat;
17308     int size;
17309     int64_t i, data_size, n_particles;
17310     void *temp;
17311     long file_pos;
17312
17313     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17314     TNG_ASSERT(values, "TNG library: The pointer to the values array must not be a NULL pointer");
17315     TNG_ASSERT(data_type, "TNG library: The pointer to the data type of the returned data must not be a NULL pointer");
17316     TNG_ASSERT(retrieved_frame_number, "TNG library: The pointer to the frame number of the returned data must not be a NULL pointer");
17317     TNG_ASSERT(retrieved_time, "TNG library: The pointer to the time of the returned data must not be a NULL pointer");
17318
17319     frame_set = &tng_data->current_trajectory_frame_set;
17320
17321     stat = tng_particle_data_find(tng_data, block_id, &data);
17322     if(stat != TNG_SUCCESS)
17323     {
17324         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17325         file_pos = ftell(tng_data->input_file);
17326         while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
17327         {
17328             stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17329             file_pos = ftell(tng_data->input_file);
17330         }
17331         if(stat != TNG_SUCCESS)
17332         {
17333             return(stat);
17334         }
17335         stat = tng_particle_data_find(tng_data, block_id, &data);
17336         if(stat != TNG_SUCCESS)
17337         {
17338             return(stat);
17339         }
17340     }
17341     if(data->last_retrieved_frame < 0)
17342     {
17343         fseek(tng_data->input_file,
17344               (long)tng_data->first_trajectory_frame_set_input_file_pos,
17345               SEEK_SET);
17346         stat = tng_frame_set_read(tng_data, TNG_USE_HASH);
17347         if(stat != TNG_SUCCESS)
17348         {
17349             return(stat);
17350         }
17351         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17352         if(stat != TNG_SUCCESS)
17353         {
17354             return(stat);
17355         }
17356
17357         i = data->first_frame_with_data;
17358     }
17359     else
17360     {
17361         if(data->n_frames == 1)
17362         {
17363             i = data->last_retrieved_frame + 1;
17364         }
17365         else
17366         {
17367             i = data->last_retrieved_frame + data->stride_length;
17368         }
17369         if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
17370         {
17371             stat = tng_frame_set_of_frame_find(tng_data, i);
17372             if(stat != TNG_SUCCESS)
17373             {
17374                 /* If the frame set search found the frame set after the starting
17375                  * frame set there is a gap in the frame sets. So, even if the frame
17376                  * was not found the next frame with data is still in the found
17377                  * frame set. */
17378                 if(stat == TNG_CRITICAL)
17379                 {
17380                     return(stat);
17381                 }
17382                 if(frame_set->first_frame + frame_set->n_frames - 1 < i)
17383                 {
17384                     return(TNG_FAILURE);
17385                 }
17386                 i = frame_set->first_frame;
17387             }
17388         }
17389         if(data->last_retrieved_frame < frame_set->first_frame)
17390         {
17391             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17392             if(stat != TNG_SUCCESS)
17393             {
17394                 return(stat);
17395             }
17396         }
17397     }
17398     data->last_retrieved_frame = i;
17399     *retrieved_frame_number = i;
17400     if(frame_set->first_frame_time >= 0 && tng_data->time_per_frame >= 0)
17401     {
17402         *retrieved_time = frame_set->first_frame_time +
17403                         (i - frame_set->first_frame) *
17404                         tng_data->time_per_frame;
17405     }
17406     else
17407     {
17408         *retrieved_time = 0;
17409     }
17410
17411     if(data->stride_length > 1)
17412     {
17413         i = (i - data->first_frame_with_data) / data->stride_length;
17414     }
17415     else
17416     {
17417         i = (i - frame_set->first_frame);
17418     }
17419
17420     tng_num_particles_get(tng_data, &n_particles);
17421
17422     *data_type = data->datatype;
17423
17424     switch(*data_type)
17425     {
17426     case TNG_CHAR_DATA:
17427         return(TNG_FAILURE);
17428     case TNG_INT_DATA:
17429         size = sizeof(int64_t);
17430         break;
17431     case TNG_FLOAT_DATA:
17432         size = sizeof(float);
17433         break;
17434     case TNG_DOUBLE_DATA:
17435     default:
17436         size = sizeof(double);
17437     }
17438
17439     data_size = size * n_particles * data->n_values_per_frame;
17440
17441 //     fprintf(stderr, "TNG library: TEMP: i = %"PRId64", data_size = %"PRId64", size = %d, n_particles = %"PRId64", n_values_per_frame = %"PRId64"\n",
17442 //            i, data_size, size, n_particles, data->n_values_per_frame);
17443
17444     temp = realloc(*values, data_size);
17445     if(!temp)
17446     {
17447         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
17448                data_size, __FILE__, __LINE__);
17449         free(*values);
17450         *values = 0;
17451         return(TNG_CRITICAL);
17452     }
17453
17454     *values = temp;
17455
17456     memcpy(*values, (char *)data->values + i * data_size, data_size);
17457
17458     return(TNG_SUCCESS);
17459 }
17460
17461 tng_function_status DECLSPECDLLEXPORT tng_util_non_particle_data_next_frame_read
17462                 (tng_trajectory_t tng_data,
17463                  const int64_t block_id,
17464                  void **values,
17465                  char *data_type,
17466                  int64_t *retrieved_frame_number,
17467                  double *retrieved_time)
17468 {
17469     tng_trajectory_frame_set_t frame_set;
17470     tng_non_particle_data_t data = 0;
17471     tng_function_status stat;
17472     int size;
17473     int64_t i, data_size;
17474     void *temp;
17475     long file_pos;
17476
17477     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17478     TNG_ASSERT(values, "TNG library: The pointer to the values array must not be a NULL pointer");
17479     TNG_ASSERT(data_type, "TNG library: The pointer to the data type of the returned data must not be a NULL pointer");
17480     TNG_ASSERT(retrieved_frame_number, "TNG library: The pointer to the frame number of the returned data must not be a NULL pointer");
17481     TNG_ASSERT(retrieved_time, "TNG library: The pointer to the time of the returned data must not be a NULL pointer");
17482
17483     frame_set = &tng_data->current_trajectory_frame_set;
17484
17485     stat = tng_data_find(tng_data, block_id, &data);
17486     if(stat != TNG_SUCCESS)
17487     {
17488         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17489         file_pos = ftell(tng_data->input_file);
17490         while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
17491         {
17492             stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17493             file_pos = ftell(tng_data->input_file);
17494         }
17495         if(stat != TNG_SUCCESS)
17496         {
17497             return(stat);
17498         }
17499         stat = tng_data_find(tng_data, block_id, &data);
17500         if(stat != TNG_SUCCESS)
17501         {
17502             return(stat);
17503         }
17504     }
17505     if(data->last_retrieved_frame < 0)
17506     {
17507         fseek(tng_data->input_file,
17508                 (long)tng_data->first_trajectory_frame_set_input_file_pos,
17509                 SEEK_SET);
17510         stat = tng_frame_set_read(tng_data, TNG_USE_HASH);
17511         if(stat != TNG_SUCCESS)
17512         {
17513             return(stat);
17514         }
17515         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17516         if(stat != TNG_SUCCESS)
17517         {
17518             return(stat);
17519         }
17520
17521         i = data->first_frame_with_data;
17522     }
17523     else
17524     {
17525         if(data->n_frames == 1)
17526         {
17527             i = data->last_retrieved_frame + 1;
17528         }
17529         else
17530         {
17531             i = data->last_retrieved_frame + data->stride_length;
17532         }
17533         if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
17534         {
17535             stat = tng_frame_set_of_frame_find(tng_data, i);
17536             if(stat != TNG_SUCCESS)
17537             {
17538                 /* If the frame set search found the frame set after the starting
17539                  * frame set there is a gap in the frame sets. So, even if the frame
17540                  * was not found the next frame with data is still in the found
17541                  * frame set. */
17542                 if(stat == TNG_CRITICAL)
17543                 {
17544                     return(stat);
17545                 }
17546                 if(frame_set->first_frame + frame_set->n_frames - 1 < i)
17547                 {
17548                     return(TNG_FAILURE);
17549                 }
17550                 i = frame_set->first_frame;
17551             }
17552         }
17553         if(data->last_retrieved_frame < frame_set->first_frame)
17554         {
17555             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17556             if(stat != TNG_SUCCESS)
17557             {
17558                 return(stat);
17559             }
17560         }
17561     }
17562     data->last_retrieved_frame = i;
17563     *retrieved_frame_number = i;
17564     if(frame_set->first_frame_time >= 0 && tng_data->time_per_frame >= 0)
17565     {
17566         *retrieved_time = frame_set->first_frame_time +
17567                         (i - frame_set->first_frame) *
17568                         tng_data->time_per_frame;
17569     }
17570     else
17571     {
17572         *retrieved_time = 0;
17573     }
17574
17575     if(data->stride_length > 1)
17576     {
17577         i = (i - data->first_frame_with_data) / data->stride_length;
17578     }
17579     else
17580     {
17581         i = (i - frame_set->first_frame);
17582     }
17583
17584     *data_type = data->datatype;
17585
17586     switch(*data_type)
17587     {
17588     case TNG_CHAR_DATA:
17589         return(TNG_FAILURE);
17590     case TNG_INT_DATA:
17591         size = sizeof(int64_t);
17592         break;
17593     case TNG_FLOAT_DATA:
17594         size = sizeof(float);
17595         break;
17596     case TNG_DOUBLE_DATA:
17597     default:
17598         size = sizeof(double);
17599     }
17600
17601     data_size = size * data->n_values_per_frame;
17602
17603     temp = realloc(*values, data_size);
17604     if(!temp)
17605     {
17606         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
17607                data_size, __FILE__, __LINE__);
17608         free(*values);
17609         *values = 0;
17610         return(TNG_CRITICAL);
17611     }
17612
17613     *values = temp;
17614
17615     memcpy(*values, (char *)data->values + i * data_size, data_size);
17616
17617     return(TNG_SUCCESS);
17618 }
17619
17620 tng_function_status DECLSPECDLLEXPORT tng_util_pos_read_range
17621                 (tng_trajectory_t tng_data,
17622                  const int64_t first_frame,
17623                  const int64_t last_frame,
17624                  float **positions,
17625                  int64_t *stride_length)
17626 {
17627     int64_t n_particles, n_values_per_frame;
17628     char type;
17629     tng_function_status stat;
17630
17631     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17632     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
17633     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
17634     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17635
17636     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_POSITIONS,
17637                                                  first_frame, last_frame,
17638                                                  TNG_USE_HASH,
17639                                                  (void **)positions,
17640                                                  &n_particles,
17641                                                  stride_length,
17642                                                  &n_values_per_frame,
17643                                                  &type);
17644
17645     return(stat);
17646 }
17647
17648 tng_function_status DECLSPECDLLEXPORT tng_util_vel_read_range
17649                 (tng_trajectory_t tng_data,
17650                  const int64_t first_frame,
17651                  const int64_t last_frame,
17652                  float **velocities,
17653                  int64_t *stride_length)
17654 {
17655     int64_t n_particles, n_values_per_frame;
17656     char type;
17657     tng_function_status stat;
17658
17659     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17660     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
17661     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
17662     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17663
17664     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_VELOCITIES,
17665                                                  first_frame, last_frame,
17666                                                  TNG_USE_HASH,
17667                                                  (void **)velocities,
17668                                                  &n_particles,
17669                                                  stride_length,
17670                                                  &n_values_per_frame,
17671                                                  &type);
17672
17673     return(stat);
17674 }
17675
17676 tng_function_status DECLSPECDLLEXPORT tng_util_force_read_range
17677                 (tng_trajectory_t tng_data,
17678                  const int64_t first_frame,
17679                  const int64_t last_frame,
17680                  float **forces,
17681                  int64_t *stride_length)
17682 {
17683     int64_t n_particles, n_values_per_frame;
17684     char type;
17685     tng_function_status stat;
17686
17687     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17688     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
17689     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
17690     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17691
17692     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_FORCES,
17693                                                  first_frame, last_frame,
17694                                                  TNG_USE_HASH,
17695                                                  (void **)forces,
17696                                                  &n_particles,
17697                                                  stride_length,
17698                                                  &n_values_per_frame,
17699                                                  &type);
17700
17701     return(stat);
17702 }
17703
17704 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_read_range
17705                 (tng_trajectory_t tng_data,
17706                  const int64_t first_frame,
17707                  const int64_t last_frame,
17708                  float **box_shape,
17709                  int64_t *stride_length)
17710 {
17711     int64_t n_values_per_frame;
17712     char type;
17713     tng_function_status stat;
17714
17715     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17716     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
17717     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
17718     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17719
17720     stat = tng_data_vector_interval_get(tng_data, TNG_TRAJ_BOX_SHAPE,
17721                                         first_frame, last_frame,
17722                                         TNG_USE_HASH,
17723                                         (void **)box_shape,
17724                                         stride_length,
17725                                         &n_values_per_frame,
17726                                         &type);
17727
17728     return(stat);
17729 }
17730
17731 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_interval_set
17732                 (tng_trajectory_t tng_data,
17733                  const int64_t i,
17734                  const int64_t n_values_per_frame,
17735                  const int64_t block_id,
17736                  const char *block_name,
17737                  const char particle_dependency,
17738                  const char compression)
17739 {
17740     tng_trajectory_frame_set_t frame_set;
17741     tng_particle_data_t p_data;
17742     tng_non_particle_data_t np_data;
17743     int64_t n_particles, n_frames;
17744     tng_function_status stat;
17745
17746     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17747     TNG_ASSERT(i >= 0, "TNG library: i (writing interval) must be >= 0.");
17748
17749     if(i <= 0)
17750     {
17751         fprintf(stderr, "TNG library: Cannot set writing frequency to %"PRId64". %s: %d\n",
17752                i, __FILE__, __LINE__);
17753         return(TNG_FAILURE);
17754     }
17755
17756     frame_set = &tng_data->current_trajectory_frame_set;
17757
17758     if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
17759     {
17760         n_frames = tng_data->frame_set_n_frames;
17761
17762         stat = tng_frame_set_new(tng_data, 0, n_frames);
17763         if(stat != TNG_SUCCESS)
17764         {
17765             fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
17766                 __LINE__);
17767             return(stat);
17768         }
17769     }
17770     else
17771     {
17772         n_frames = frame_set->n_frames;
17773     }
17774
17775     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
17776     {
17777         tng_num_particles_get(tng_data, &n_particles);
17778         if(n_particles <= 0)
17779         {
17780             return(TNG_FAILURE);
17781         }
17782
17783         if(tng_particle_data_find(tng_data, block_id, &p_data)
17784         != TNG_SUCCESS)
17785         {
17786             stat = tng_particle_data_block_add(tng_data, block_id,
17787                                                block_name,
17788                                                TNG_FLOAT_DATA,
17789                                                TNG_TRAJECTORY_BLOCK,
17790                                                n_frames, n_values_per_frame, i,
17791                                                0, n_particles,
17792                                                compression, 0);
17793             if(stat != TNG_SUCCESS)
17794             {
17795                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17796                        __FILE__, __LINE__);
17797                 return(stat);
17798             }
17799             p_data = &frame_set->tr_particle_data[frame_set->
17800                                                   n_particle_data_blocks - 1];
17801             stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
17802                                                   i, n_particles,
17803                                                   n_values_per_frame);
17804             if(stat != TNG_SUCCESS)
17805             {
17806                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17807                        __FILE__, __LINE__);
17808                 return(stat);
17809             }
17810         }
17811         else
17812         {
17813             if(p_data->stride_length != i)
17814             {
17815                 p_data->stride_length = i;
17816                 stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
17817                                                       i, n_particles,
17818                                                       n_values_per_frame);
17819                 if(stat != TNG_SUCCESS)
17820                 {
17821                     fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17822                            __FILE__, __LINE__);
17823                     return(stat);
17824                 }
17825             }
17826         }
17827     }
17828     else
17829     {
17830         if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
17831         {
17832             stat = tng_data_block_add(tng_data, block_id, block_name,
17833                                       TNG_FLOAT_DATA, TNG_TRAJECTORY_BLOCK,
17834                                       n_frames, n_values_per_frame,
17835                                       i, compression, 0);
17836             if(stat != TNG_SUCCESS)
17837             {
17838                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17839                        __FILE__, __LINE__);
17840                 return(stat);
17841             }
17842             np_data = &frame_set->tr_data[frame_set->
17843                                           n_data_blocks - 1];
17844             stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
17845                                          i, n_values_per_frame);
17846             if(stat != TNG_SUCCESS)
17847             {
17848                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17849                        __FILE__, __LINE__);
17850                 return(stat);
17851             }
17852         }
17853         else
17854         {
17855             if(np_data->stride_length != i)
17856             {
17857                 np_data->stride_length = i;
17858                 stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
17859                                              i, n_values_per_frame);
17860                 if(stat != TNG_SUCCESS)
17861                 {
17862                     fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17863                            __FILE__, __LINE__);
17864                     return(stat);
17865                 }
17866             }
17867         }
17868     }
17869
17870     return(TNG_SUCCESS);
17871 }
17872
17873 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_interval_double_set
17874                 (tng_trajectory_t tng_data,
17875                  const int64_t i,
17876                  const int64_t n_values_per_frame,
17877                  const int64_t block_id,
17878                  const char *block_name,
17879                  const char particle_dependency,
17880                  const char compression)
17881 {
17882     tng_trajectory_frame_set_t frame_set;
17883     tng_particle_data_t p_data;
17884     tng_non_particle_data_t np_data;
17885     int64_t n_particles, n_frames;
17886     tng_function_status stat;
17887
17888     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17889     TNG_ASSERT(i >= 0, "TNG library: i (writing interval) must be >= 0.");
17890
17891     if(i <= 0)
17892     {
17893         fprintf(stderr, "TNG library: Cannot set writing frequency to %"PRId64". %s: %d\n",
17894                i, __FILE__, __LINE__);
17895         return(TNG_FAILURE);
17896     }
17897
17898     frame_set = &tng_data->current_trajectory_frame_set;
17899
17900     if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
17901     {
17902         n_frames = tng_data->frame_set_n_frames;
17903
17904         stat = tng_frame_set_new(tng_data, 0, n_frames);
17905         if(stat != TNG_SUCCESS)
17906         {
17907             fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
17908                 __LINE__);
17909             return(stat);
17910         }
17911     }
17912     else
17913     {
17914         n_frames = frame_set->n_frames;
17915     }
17916
17917     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
17918     {
17919         tng_num_particles_get(tng_data, &n_particles);
17920
17921         if(n_particles <= 0)
17922         {
17923             return(TNG_FAILURE);
17924         }
17925
17926         if(tng_particle_data_find(tng_data, block_id, &p_data)
17927         != TNG_SUCCESS)
17928         {
17929             stat = tng_particle_data_block_add(tng_data, block_id,
17930                                             block_name,
17931                                             TNG_DOUBLE_DATA,
17932                                             TNG_TRAJECTORY_BLOCK,
17933                                             n_frames, n_values_per_frame, i,
17934                                             0, n_particles,
17935                                             compression, 0);
17936             if(stat != TNG_SUCCESS)
17937             {
17938                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17939                        __FILE__, __LINE__);
17940                 return(stat);
17941             }
17942             p_data = &frame_set->tr_particle_data[frame_set->
17943                                                   n_particle_data_blocks - 1];
17944             stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
17945                                                   i, n_particles,
17946                                                   n_values_per_frame);
17947             if(stat != TNG_SUCCESS)
17948             {
17949                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17950                        __FILE__, __LINE__);
17951                 return(stat);
17952             }
17953         }
17954         else
17955         {
17956             p_data->stride_length = i;
17957         }
17958     }
17959     else
17960     {
17961         if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
17962         {
17963             stat = tng_data_block_add(tng_data, block_id, block_name,
17964                                       TNG_DOUBLE_DATA, TNG_TRAJECTORY_BLOCK,
17965                                       n_frames, n_values_per_frame,
17966                                       i, compression, 0);
17967             if(stat != TNG_SUCCESS)
17968             {
17969                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17970                        __FILE__, __LINE__);
17971                 return(stat);
17972             }
17973             np_data = &frame_set->tr_data[frame_set->
17974                                           n_data_blocks - 1];
17975             stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
17976                                          i, n_values_per_frame);
17977             if(stat != TNG_SUCCESS)
17978             {
17979                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17980                        __FILE__, __LINE__);
17981                 return(stat);
17982             }
17983         }
17984         else
17985         {
17986             np_data->stride_length = i;
17987         }
17988     }
17989
17990     return(TNG_SUCCESS);
17991 }
17992
17993 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_frequency_set
17994                 (tng_trajectory_t tng_data,
17995                  const int64_t i,
17996                  const int64_t n_values_per_frame,
17997                  const int64_t block_id,
17998                  const char *block_name,
17999                  const char particle_dependency,
18000                  const char compression)
18001 {
18002     fprintf(stderr, "TNG library: Using obsolete function tng_util_generic_write_frequency_set(). "
18003            "See documentation. %s: %d", __FILE__, __LINE__);
18004     return(tng_util_generic_write_interval_set(tng_data, i, n_values_per_frame,
18005                                                block_id, block_name,
18006                                                particle_dependency,
18007                                                compression));
18008 }
18009 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_interval_set
18010                 (tng_trajectory_t tng_data,
18011                  const int64_t i)
18012 {
18013     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18014     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18015
18016     return(tng_util_generic_write_interval_set(tng_data, i, 3,
18017                                                TNG_TRAJ_POSITIONS,
18018                                                "POSITIONS",
18019                                                TNG_PARTICLE_BLOCK_DATA,
18020                                                TNG_TNG_COMPRESSION));
18021 }
18022
18023 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_interval_double_set
18024                 (tng_trajectory_t tng_data,
18025                  const int64_t i)
18026 {
18027     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18028     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18029
18030     return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
18031                                                       TNG_TRAJ_POSITIONS,
18032                                                       "POSITIONS",
18033                                                       TNG_PARTICLE_BLOCK_DATA,
18034                                                       TNG_TNG_COMPRESSION));
18035 }
18036
18037 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_frequency_set
18038                 (tng_trajectory_t tng_data,
18039                  const int64_t i)
18040 {
18041     fprintf(stderr, "TNG library: Using obsolete function tng_util_pos_write_frequency_set(). "
18042            "See documentation. %s: %d", __FILE__, __LINE__);
18043     return(tng_util_pos_write_interval_set(tng_data, i));
18044 }
18045
18046 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_interval_set
18047                 (tng_trajectory_t tng_data,
18048                  const int64_t i)
18049 {
18050     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18051     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18052
18053     return(tng_util_generic_write_interval_set(tng_data, i, 3,
18054                                                TNG_TRAJ_VELOCITIES,
18055                                                "VELOCITIES",
18056                                                TNG_PARTICLE_BLOCK_DATA,
18057                                                TNG_TNG_COMPRESSION));
18058 }
18059
18060 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_interval_double_set
18061                 (tng_trajectory_t tng_data,
18062                  const int64_t i)
18063 {
18064     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18065     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18066
18067     return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
18068                                                       TNG_TRAJ_VELOCITIES,
18069                                                       "VELOCITIES",
18070                                                       TNG_PARTICLE_BLOCK_DATA,
18071                                                       TNG_TNG_COMPRESSION));
18072 }
18073
18074 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_frequency_set
18075                 (tng_trajectory_t tng_data,
18076                  const int64_t i)
18077 {
18078     fprintf(stderr, "TNG library: Using obsolete function tng_util_vel_write_frequency_set(). "
18079            "See documentation. %s: %d", __FILE__, __LINE__);
18080     return(tng_util_vel_write_interval_set(tng_data, i));
18081 }
18082
18083 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_interval_set
18084                 (tng_trajectory_t tng_data,
18085                  const int64_t i)
18086 {
18087     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18088     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18089
18090     return(tng_util_generic_write_interval_set(tng_data, i, 3,
18091                                                TNG_TRAJ_FORCES,
18092                                                "FORCES",
18093                                                TNG_PARTICLE_BLOCK_DATA,
18094                                                TNG_GZIP_COMPRESSION));
18095 }
18096
18097 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_interval_double_set
18098                 (tng_trajectory_t tng_data,
18099                  const int64_t i)
18100 {
18101     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18102     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18103
18104     return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
18105                                                       TNG_TRAJ_FORCES,
18106                                                       "FORCES",
18107                                                       TNG_PARTICLE_BLOCK_DATA,
18108                                                       TNG_GZIP_COMPRESSION));
18109 }
18110
18111 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_frequency_set
18112                 (tng_trajectory_t tng_data,
18113                  const int64_t i)
18114 {
18115     fprintf(stderr, "TNG library: Using obsolete function tng_util_force_write_frequency_set(). "
18116            "See documentation. %s: %d", __FILE__, __LINE__);
18117     return(tng_util_force_write_interval_set(tng_data, i));
18118 }
18119
18120 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_interval_set
18121                 (tng_trajectory_t tng_data,
18122                  const int64_t i)
18123 {
18124     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18125     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18126
18127     return(tng_util_generic_write_interval_set(tng_data, i, 9,
18128                                                TNG_TRAJ_BOX_SHAPE,
18129                                                "BOX SHAPE",
18130                                                TNG_NON_PARTICLE_BLOCK_DATA,
18131                                                TNG_GZIP_COMPRESSION));
18132 }
18133
18134 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_interval_double_set
18135                 (tng_trajectory_t tng_data,
18136                  const int64_t i)
18137 {
18138     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18139     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18140
18141     return(tng_util_generic_write_interval_double_set(tng_data, i, 9,
18142                                                       TNG_TRAJ_BOX_SHAPE,
18143                                                       "BOX SHAPE",
18144                                                       TNG_NON_PARTICLE_BLOCK_DATA,
18145                                                       TNG_GZIP_COMPRESSION));
18146 }
18147
18148 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_frequency_set
18149                 (tng_trajectory_t tng_data,
18150                  const int64_t i)
18151 {
18152     fprintf(stderr, "TNG library: Using obsolete function tng_util_box_shape_write_frequency_set(). "
18153            "See documentation. %s: %d", __FILE__, __LINE__);
18154     return(tng_util_box_shape_write_interval_set(tng_data, i));
18155 }
18156
18157 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write
18158                 (tng_trajectory_t tng_data,
18159                  const int64_t frame_nr,
18160                  const float *values,
18161                  const int64_t n_values_per_frame,
18162                  const int64_t block_id,
18163                  const char *block_name,
18164                  const char particle_dependency,
18165                  const char compression)
18166 {
18167     tng_trajectory_frame_set_t frame_set;
18168     tng_particle_data_t p_data;
18169     tng_non_particle_data_t np_data;
18170     int64_t n_particles = 0, n_frames, stride_length = 100, frame_pos;
18171     int64_t last_frame;
18172     int is_first_frame_flag = 0;
18173     char block_type_flag;
18174     tng_function_status stat;
18175
18176     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18177     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18178     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
18179
18180     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
18181     {
18182         tng_num_particles_get(tng_data, &n_particles);
18183         TNG_ASSERT(n_particles > 0, "TNG library: There must be particles in the system to write particle data.");
18184     }
18185
18186     if(values == 0)
18187     {
18188         return(TNG_FAILURE);
18189     }
18190
18191     frame_set = &tng_data->current_trajectory_frame_set;
18192
18193     if(frame_nr < 0)
18194     {
18195         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
18196         n_frames = stride_length = 1;
18197     }
18198     else
18199     {
18200         block_type_flag = TNG_TRAJECTORY_BLOCK;
18201
18202         if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
18203         {
18204             stat = tng_frame_set_new(tng_data, 0, tng_data->frame_set_n_frames);
18205             if(stat != TNG_SUCCESS)
18206             {
18207                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
18208                     __LINE__);
18209                 return(stat);
18210             }
18211         }
18212         last_frame = frame_set->first_frame +
18213                      frame_set->n_frames - 1;
18214         if(frame_nr > last_frame)
18215         {
18216             stat = tng_frame_set_write(tng_data, TNG_USE_HASH);
18217             if(stat != TNG_SUCCESS)
18218             {
18219                 fprintf(stderr, "TNG library: Cannot write frame set.  %s: %d\n", __FILE__,
18220                     __LINE__);
18221                 return(stat);
18222             }
18223             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
18224             {
18225                 last_frame = frame_nr - 1;
18226             }
18227             stat = tng_frame_set_new(tng_data, last_frame + 1,
18228                                      tng_data->frame_set_n_frames);
18229             if(stat != TNG_SUCCESS)
18230             {
18231                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
18232                     __LINE__);
18233                 return(stat);
18234             }
18235         }
18236         if(frame_set->n_unwritten_frames == 0)
18237         {
18238             is_first_frame_flag = 1;
18239         }
18240         frame_set->n_unwritten_frames = frame_nr -
18241                                         frame_set->first_frame + 1;
18242
18243         n_frames = frame_set->n_frames;
18244     }
18245
18246     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
18247     {
18248         if(tng_particle_data_find(tng_data, block_id, &p_data)
18249         != TNG_SUCCESS)
18250         {
18251             stat = tng_particle_data_block_add(tng_data, block_id,
18252                                                block_name,
18253                                                TNG_FLOAT_DATA,
18254                                                block_type_flag,
18255                                                n_frames, n_values_per_frame,
18256                                                stride_length,
18257                                                0, n_particles,
18258                                                compression, 0);
18259             if(stat != TNG_SUCCESS)
18260             {
18261                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
18262                        __FILE__, __LINE__);
18263                 return(stat);
18264             }
18265             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18266             {
18267                 p_data = &frame_set->tr_particle_data[frame_set->
18268                                                     n_particle_data_blocks - 1];
18269             }
18270             else
18271             {
18272                 p_data = &tng_data->non_tr_particle_data[tng_data->
18273                                                     n_particle_data_blocks - 1];
18274             }
18275             stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
18276                                                   stride_length, n_particles,
18277                                                   n_values_per_frame);
18278             if(stat != TNG_SUCCESS)
18279             {
18280                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
18281                        __FILE__, __LINE__);
18282                 return(stat);
18283             }
18284         }
18285
18286         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18287         {
18288             stride_length = p_data->stride_length;
18289
18290             if(is_first_frame_flag || p_data->first_frame_with_data < frame_set->first_frame)
18291             {
18292                 p_data->first_frame_with_data = frame_nr;
18293                 frame_pos = 0;
18294             }
18295             else
18296             {
18297                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
18298             }
18299
18300             memcpy((char *)p_data->values + sizeof(float) * frame_pos * n_particles *
18301                    n_values_per_frame, values, sizeof(float) *
18302                    n_particles * n_values_per_frame);
18303         }
18304         else
18305         {
18306             memcpy(p_data->values, values, sizeof(float) * n_particles *
18307                    n_values_per_frame);
18308         }
18309     }
18310     else
18311     {
18312         if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
18313         {
18314             stat = tng_data_block_add(tng_data, block_id, block_name,
18315                                       TNG_FLOAT_DATA, block_type_flag,
18316                                       n_frames, n_values_per_frame,
18317                                       stride_length, compression, 0);
18318             if(stat != TNG_SUCCESS)
18319             {
18320                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
18321                        __FILE__, __LINE__);
18322                 return(stat);
18323             }
18324             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18325             {
18326                 np_data = &frame_set->tr_data[frame_set->
18327                                               n_data_blocks - 1];
18328             }
18329             else
18330             {
18331                 np_data = &tng_data->non_tr_data[tng_data->
18332                                                  n_data_blocks - 1];
18333             }
18334             stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
18335                                          stride_length, n_values_per_frame);
18336             if(stat != TNG_SUCCESS)
18337             {
18338                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
18339                        __FILE__, __LINE__);
18340                 return(stat);
18341             }
18342         }
18343
18344         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18345         {
18346             stride_length = np_data->stride_length;
18347
18348             if(is_first_frame_flag || np_data->first_frame_with_data < frame_set->first_frame)
18349             {
18350                 np_data->first_frame_with_data = frame_nr;
18351                 frame_pos = 0;
18352             }
18353             else
18354             {
18355                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
18356             }
18357
18358             memcpy((char *)np_data->values + sizeof(float) * frame_pos *
18359                    n_values_per_frame, values, sizeof(float) *
18360                    n_values_per_frame);
18361         }
18362         else
18363         {
18364             memcpy(np_data->values, values, sizeof(float) * n_values_per_frame);
18365         }
18366     }
18367
18368     return(TNG_SUCCESS);
18369 }
18370
18371 tng_function_status DECLSPECDLLEXPORT tng_util_generic_double_write
18372                 (tng_trajectory_t tng_data,
18373                  const int64_t frame_nr,
18374                  const double *values,
18375                  const int64_t n_values_per_frame,
18376                  const int64_t block_id,
18377                  const char *block_name,
18378                  const char particle_dependency,
18379                  const char compression)
18380 {
18381     tng_trajectory_frame_set_t frame_set;
18382     tng_particle_data_t p_data;
18383     tng_non_particle_data_t np_data;
18384     int64_t n_particles = 0, n_frames, stride_length = 100, frame_pos;
18385     int64_t last_frame;
18386     int is_first_frame_flag = 0;
18387     char block_type_flag;
18388     tng_function_status stat;
18389
18390     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18391     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18392     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
18393
18394     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
18395     {
18396         tng_num_particles_get(tng_data, &n_particles);
18397         TNG_ASSERT(n_particles > 0, "TNG library: There must be particles in the system to write particle data.");
18398     }
18399
18400     if(values == 0)
18401     {
18402         return(TNG_FAILURE);
18403     }
18404
18405     frame_set = &tng_data->current_trajectory_frame_set;
18406
18407     if(frame_nr < 0)
18408     {
18409         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
18410         n_frames = stride_length = 1;
18411     }
18412     else
18413     {
18414         block_type_flag = TNG_TRAJECTORY_BLOCK;
18415
18416         n_frames = tng_data->frame_set_n_frames;
18417
18418         if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
18419         {
18420             stat = tng_frame_set_new(tng_data, 0, n_frames);
18421             if(stat != TNG_SUCCESS)
18422             {
18423                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
18424                     __LINE__);
18425                 return(stat);
18426             }
18427         }
18428         else
18429         {
18430             n_frames = frame_set->n_frames;
18431         }
18432         last_frame = frame_set->first_frame +
18433                      frame_set->n_frames - 1;
18434         if(frame_nr > last_frame)
18435         {
18436             stat = tng_frame_set_write(tng_data, TNG_USE_HASH);
18437             if(stat != TNG_SUCCESS)
18438             {
18439                 fprintf(stderr, "TNG library: Cannot write frame set.  %s: %d\n", __FILE__,
18440                     __LINE__);
18441                 return(stat);
18442             }
18443             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
18444             {
18445                 last_frame = frame_nr - 1;
18446             }
18447             stat = tng_frame_set_new(tng_data, last_frame + 1, n_frames);
18448             if(stat != TNG_SUCCESS)
18449             {
18450                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
18451                     __LINE__);
18452                 return(stat);
18453             }
18454         }
18455         if(frame_set->n_unwritten_frames == 0)
18456         {
18457             is_first_frame_flag = 1;
18458         }
18459         frame_set->n_unwritten_frames = frame_nr -
18460                                         frame_set->first_frame + 1;
18461     }
18462
18463     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
18464     {
18465         if(tng_particle_data_find(tng_data, block_id, &p_data)
18466         != TNG_SUCCESS)
18467         {
18468             stat = tng_particle_data_block_add(tng_data, block_id,
18469                                             block_name,
18470                                             TNG_DOUBLE_DATA,
18471                                             block_type_flag,
18472                                             n_frames, n_values_per_frame,
18473                                             stride_length,
18474                                             0, n_particles,
18475                                             compression, 0);
18476             if(stat != TNG_SUCCESS)
18477             {
18478                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
18479                        __FILE__, __LINE__);
18480                 return(stat);
18481             }
18482             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18483             {
18484                 p_data = &frame_set->tr_particle_data[frame_set->
18485                                                     n_particle_data_blocks - 1];
18486             }
18487             else
18488             {
18489                 p_data = &tng_data->non_tr_particle_data[tng_data->
18490                                                     n_particle_data_blocks - 1];
18491             }
18492             stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
18493                                                   stride_length, n_particles,
18494                                                   n_values_per_frame);
18495             if(stat != TNG_SUCCESS)
18496             {
18497                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
18498                        __FILE__, __LINE__);
18499                 return(stat);
18500             }
18501         }
18502
18503         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18504         {
18505             stride_length = p_data->stride_length;
18506
18507             if(is_first_frame_flag)
18508             {
18509                 p_data->first_frame_with_data = frame_nr;
18510                 frame_pos = 0;
18511             }
18512             else
18513             {
18514                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
18515             }
18516
18517             memcpy((char *)p_data->values + sizeof(double) * frame_pos * n_particles *
18518                    n_values_per_frame, values, sizeof(double) *
18519                    n_particles * n_values_per_frame);
18520         }
18521         else
18522         {
18523             memcpy(p_data->values, values, sizeof(double) * n_particles *
18524                    n_values_per_frame);
18525         }
18526     }
18527     else
18528     {
18529         if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
18530         {
18531             stat = tng_data_block_add(tng_data, block_id, block_name,
18532                                       TNG_DOUBLE_DATA, block_type_flag,
18533                                       n_frames, n_values_per_frame,
18534                                       stride_length, compression, 0);
18535             if(stat != TNG_SUCCESS)
18536             {
18537                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
18538                        __FILE__, __LINE__);
18539                 return(stat);
18540             }
18541             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18542             {
18543                 np_data = &frame_set->tr_data[frame_set->
18544                                               n_data_blocks - 1];
18545             }
18546             else
18547             {
18548                 np_data = &tng_data->non_tr_data[tng_data->
18549                                                  n_data_blocks - 1];
18550             }
18551             stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
18552                                          stride_length, n_values_per_frame);
18553             if(stat != TNG_SUCCESS)
18554             {
18555                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
18556                        __FILE__, __LINE__);
18557                 return(stat);
18558             }
18559         }
18560
18561         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18562         {
18563             stride_length = np_data->stride_length;
18564
18565             if(is_first_frame_flag)
18566             {
18567                 np_data->first_frame_with_data = frame_nr;
18568                 frame_pos = 0;
18569             }
18570             else
18571             {
18572                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
18573             }
18574
18575             memcpy((char *)np_data->values + sizeof(double) * frame_pos *
18576                    n_values_per_frame, values, sizeof(double) *
18577                    n_values_per_frame);
18578         }
18579         else
18580         {
18581             memcpy(np_data->values, values, sizeof(double) * n_values_per_frame);
18582         }
18583     }
18584
18585     return(TNG_SUCCESS);
18586 }
18587
18588 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write
18589                 (tng_trajectory_t tng_data,
18590                  const int64_t frame_nr,
18591                  const float *positions)
18592 {
18593     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18594     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18595     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
18596
18597     return(tng_util_generic_write(tng_data, frame_nr, positions, 3,
18598                                   TNG_TRAJ_POSITIONS, "POSITIONS",
18599                                   TNG_PARTICLE_BLOCK_DATA,
18600                                   TNG_TNG_COMPRESSION));
18601 }
18602
18603 tng_function_status DECLSPECDLLEXPORT tng_util_pos_double_write
18604                 (tng_trajectory_t tng_data,
18605                  const int64_t frame_nr,
18606                  const double *positions)
18607 {
18608     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18609     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18610     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
18611
18612     return(tng_util_generic_double_write(tng_data, frame_nr, positions, 3,
18613                                          TNG_TRAJ_POSITIONS, "POSITIONS",
18614                                          TNG_PARTICLE_BLOCK_DATA,
18615                                          TNG_TNG_COMPRESSION));
18616 }
18617
18618 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write
18619                 (tng_trajectory_t tng_data,
18620                  const int64_t frame_nr,
18621                  const float *velocities)
18622 {
18623     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18624     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18625     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
18626
18627     return(tng_util_generic_write(tng_data, frame_nr, velocities, 3,
18628                                   TNG_TRAJ_VELOCITIES, "VELOCITIES",
18629                                   TNG_PARTICLE_BLOCK_DATA,
18630                                   TNG_TNG_COMPRESSION));
18631 }
18632
18633 tng_function_status DECLSPECDLLEXPORT tng_util_vel_double_write
18634                 (tng_trajectory_t tng_data,
18635                  const int64_t frame_nr,
18636                  const double *velocities)
18637 {
18638     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18639     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18640     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
18641
18642     return(tng_util_generic_double_write(tng_data, frame_nr, velocities, 3,
18643                                          TNG_TRAJ_VELOCITIES, "VELOCITIES",
18644                                          TNG_PARTICLE_BLOCK_DATA,
18645                                          TNG_TNG_COMPRESSION));
18646 }
18647
18648 tng_function_status DECLSPECDLLEXPORT tng_util_force_write
18649                 (tng_trajectory_t tng_data,
18650                  const int64_t frame_nr,
18651                  const float *forces)
18652 {
18653     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18654     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18655     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
18656
18657     return(tng_util_generic_write(tng_data, frame_nr, forces, 3,
18658                                   TNG_TRAJ_FORCES, "FORCES",
18659                                   TNG_PARTICLE_BLOCK_DATA,
18660                                   TNG_GZIP_COMPRESSION));
18661 }
18662
18663 tng_function_status DECLSPECDLLEXPORT tng_util_force_double_write
18664                 (tng_trajectory_t tng_data,
18665                  const int64_t frame_nr,
18666                  const double *forces)
18667 {
18668     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18669     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18670     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
18671
18672     return(tng_util_generic_double_write(tng_data, frame_nr, forces, 3,
18673                                          TNG_TRAJ_FORCES, "FORCES",
18674                                          TNG_PARTICLE_BLOCK_DATA,
18675                                          TNG_GZIP_COMPRESSION));
18676 }
18677
18678 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write
18679                 (tng_trajectory_t tng_data,
18680                  const int64_t frame_nr,
18681                  const float *box_shape)
18682 {
18683     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18684     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18685     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
18686
18687     return(tng_util_generic_write(tng_data, frame_nr, box_shape, 9,
18688                                   TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
18689                                   TNG_NON_PARTICLE_BLOCK_DATA,
18690                                   TNG_GZIP_COMPRESSION));
18691 }
18692
18693 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_double_write
18694                 (tng_trajectory_t tng_data,
18695                  const int64_t frame_nr,
18696                  const double *box_shape)
18697 {
18698     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18699     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18700     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
18701
18702     return(tng_util_generic_double_write(tng_data, frame_nr, box_shape, 9,
18703                                          TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
18704                                          TNG_NON_PARTICLE_BLOCK_DATA,
18705                                          TNG_GZIP_COMPRESSION));
18706 }
18707
18708 tng_function_status DECLSPECDLLEXPORT tng_util_generic_with_time_write
18709                 (tng_trajectory_t tng_data,
18710                  const int64_t frame_nr,
18711                  const double time,
18712                  const float *values,
18713                  const int64_t n_values_per_frame,
18714                  const int64_t block_id,
18715                  const char *block_name,
18716                  const char particle_dependency,
18717                  const char compression)
18718 {
18719     tng_trajectory_frame_set_t frame_set;
18720     tng_function_status stat;
18721
18722     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18723     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18724     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18725     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
18726
18727     stat = tng_util_generic_write(tng_data, frame_nr, values, n_values_per_frame,
18728                                   block_id, block_name,
18729                                   particle_dependency,
18730                                   compression);
18731
18732     if(stat != TNG_SUCCESS)
18733     {
18734         return(stat);
18735     }
18736
18737     frame_set = &tng_data->current_trajectory_frame_set;
18738
18739     /* first_frame_time is -1 when it is not yet set. */
18740     if(frame_set->first_frame_time < -0.1)
18741     {
18742         if(frame_nr > frame_set->first_frame)
18743         {
18744             stat = tng_frame_set_first_frame_time_set(tng_data,
18745                                                       time -
18746                                                       (frame_nr -
18747                                                        frame_set->first_frame) *
18748                                                       tng_data->time_per_frame);
18749         }
18750         else
18751         {
18752             stat = tng_frame_set_first_frame_time_set(tng_data, time);
18753         }
18754     }
18755     return(stat);
18756 }
18757
18758 tng_function_status DECLSPECDLLEXPORT tng_util_generic_with_time_double_write
18759                 (tng_trajectory_t tng_data,
18760                  const int64_t frame_nr,
18761                  const double time,
18762                  const double *values,
18763                  const int64_t n_values_per_frame,
18764                  const int64_t block_id,
18765                  const char *block_name,
18766                  const char particle_dependency,
18767                  const char compression)
18768 {
18769     tng_trajectory_frame_set_t frame_set;
18770     tng_function_status stat;
18771
18772     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18773     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18774     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18775     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
18776
18777     stat = tng_util_generic_double_write(tng_data, frame_nr, values, n_values_per_frame,
18778                                          block_id, block_name,
18779                                          particle_dependency,
18780                                          compression);
18781
18782     if(stat != TNG_SUCCESS)
18783     {
18784         return(stat);
18785     }
18786
18787     frame_set = &tng_data->current_trajectory_frame_set;
18788
18789     /* first_frame_time is -1 when it is not yet set. */
18790     if(frame_set->first_frame_time < -0.1)
18791     {
18792         if(frame_nr > frame_set->first_frame)
18793         {
18794             stat = tng_frame_set_first_frame_time_set(tng_data,
18795                                                       time -
18796                                                       (frame_nr -
18797                                                        frame_set->first_frame) *
18798                                                       tng_data->time_per_frame);
18799         }
18800         else
18801         {
18802             stat = tng_frame_set_first_frame_time_set(tng_data, time);
18803         }
18804     }
18805     return(stat);
18806 }
18807
18808 tng_function_status DECLSPECDLLEXPORT tng_util_pos_with_time_write
18809                 (tng_trajectory_t tng_data,
18810                  const int64_t frame_nr,
18811                  const double time,
18812                  const float *positions)
18813 {
18814     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18815     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18816     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18817     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
18818
18819     return(tng_util_generic_with_time_write(tng_data, frame_nr, time, positions,
18820                                             3, TNG_TRAJ_POSITIONS, "POSITIONS",
18821                                             TNG_PARTICLE_BLOCK_DATA,
18822                                             TNG_TNG_COMPRESSION));
18823 }
18824
18825 tng_function_status DECLSPECDLLEXPORT tng_util_pos_with_time_double_write
18826                 (tng_trajectory_t tng_data,
18827                  const int64_t frame_nr,
18828                  const double time,
18829                  const double *positions)
18830 {
18831     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18832     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18833     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18834     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
18835
18836     return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
18837                                                    positions, 3,
18838                                                    TNG_TRAJ_POSITIONS,
18839                                                    "POSITIONS",
18840                                                    TNG_PARTICLE_BLOCK_DATA,
18841                                                    TNG_TNG_COMPRESSION));
18842 }
18843
18844 tng_function_status DECLSPECDLLEXPORT tng_util_vel_with_time_write
18845                 (tng_trajectory_t tng_data,
18846                  const int64_t frame_nr,
18847                  const double time,
18848                  const float *velocities)
18849 {
18850     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18851     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18852     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18853     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
18854
18855     return(tng_util_generic_with_time_write(tng_data, frame_nr, time,
18856                                             velocities, 3,
18857                                             TNG_TRAJ_VELOCITIES,
18858                                             "VELOCITIES",
18859                                             TNG_PARTICLE_BLOCK_DATA,
18860                                             TNG_TNG_COMPRESSION));
18861 }
18862
18863 tng_function_status DECLSPECDLLEXPORT tng_util_vel_with_time_double_write
18864                 (tng_trajectory_t tng_data,
18865                  const int64_t frame_nr,
18866                  const double time,
18867                  const double *velocities)
18868 {
18869     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18870     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18871     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18872     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
18873
18874     return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
18875                                                    velocities, 3,
18876                                                    TNG_TRAJ_VELOCITIES,
18877                                                    "VELOCITIES",
18878                                                    TNG_PARTICLE_BLOCK_DATA,
18879                                                    TNG_TNG_COMPRESSION));
18880 }
18881
18882 tng_function_status DECLSPECDLLEXPORT tng_util_force_with_time_write
18883                 (tng_trajectory_t tng_data,
18884                  const int64_t frame_nr,
18885                  const double time,
18886                  const float *forces)
18887 {
18888     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18889     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18890     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18891     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
18892
18893     return(tng_util_generic_with_time_write(tng_data, frame_nr, time, forces,
18894                                             3, TNG_TRAJ_FORCES, "FORCES",
18895                                             TNG_PARTICLE_BLOCK_DATA,
18896                                             TNG_GZIP_COMPRESSION));
18897 }
18898
18899 tng_function_status DECLSPECDLLEXPORT tng_util_force_with_time_double_write
18900                 (tng_trajectory_t tng_data,
18901                  const int64_t frame_nr,
18902                  const double time,
18903                  const double *forces)
18904 {
18905     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18906     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18907     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18908     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
18909
18910     return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
18911                                                    forces, 3,
18912                                                    TNG_TRAJ_FORCES, "FORCES",
18913                                                    TNG_PARTICLE_BLOCK_DATA,
18914                                                    TNG_GZIP_COMPRESSION));
18915 }
18916
18917 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_with_time_write
18918                 (tng_trajectory_t tng_data,
18919                  const int64_t frame_nr,
18920                  const double time,
18921                  const float *box_shape)
18922 {
18923     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18924     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18925     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18926     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
18927
18928     return(tng_util_generic_with_time_write(tng_data, frame_nr, time, box_shape,
18929                                             9, TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
18930                                             TNG_NON_PARTICLE_BLOCK_DATA,
18931                                             TNG_GZIP_COMPRESSION));
18932 }
18933
18934 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_with_time_double_write
18935                 (tng_trajectory_t tng_data,
18936                  const int64_t frame_nr,
18937                  const double time,
18938                  const double *box_shape)
18939 {
18940     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18941     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18942     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18943     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
18944
18945     return(tng_util_generic_with_time_double_write(tng_data, frame_nr,
18946                                                    time, box_shape, 9,
18947                                                    TNG_TRAJ_BOX_SHAPE,
18948                                                    "BOX SHAPE",
18949                                                    TNG_NON_PARTICLE_BLOCK_DATA,
18950                                                    TNG_GZIP_COMPRESSION));
18951 }
18952
18953 tng_function_status DECLSPECDLLEXPORT tng_util_frame_current_compression_get
18954                 (tng_trajectory_t tng_data,
18955                  const int64_t block_id,
18956                  int64_t *codec_id,
18957                  double *factor)
18958 {
18959     tng_trajectory_frame_set_t frame_set;
18960     tng_particle_data_t p_data = 0;
18961     tng_non_particle_data_t np_data = 0;
18962     tng_function_status stat;
18963     int64_t i;
18964     int block_type = -1;
18965
18966     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18967     TNG_ASSERT(codec_id, "TNG library: The pointer to the returned codec id must not be a NULL pointer.");
18968     TNG_ASSERT(factor, "TNG library: The pointer to the returned multiplication factor must not be a NULL pointer.");
18969
18970     frame_set = &tng_data->current_trajectory_frame_set;
18971
18972     stat = tng_particle_data_find(tng_data, block_id, &p_data);
18973     if(stat == TNG_SUCCESS)
18974     {
18975         block_type = TNG_PARTICLE_BLOCK_DATA;
18976     }
18977     else
18978     {
18979         stat = tng_data_find(tng_data, block_id, &np_data);
18980         if(stat == TNG_SUCCESS)
18981         {
18982             block_type = TNG_NON_PARTICLE_BLOCK_DATA;
18983         }
18984         else
18985         {
18986             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
18987             if(stat != TNG_SUCCESS)
18988             {
18989                 return(stat);
18990             }
18991             stat = tng_particle_data_find(tng_data, block_id, &p_data);
18992             if(stat == TNG_SUCCESS)
18993             {
18994                 block_type = TNG_PARTICLE_BLOCK_DATA;
18995             }
18996             else
18997             {
18998                 stat = tng_data_find(tng_data, block_id, &np_data);
18999                 if(stat == TNG_SUCCESS)
19000                 {
19001                     block_type = TNG_NON_PARTICLE_BLOCK_DATA;
19002                 }
19003                 else
19004                 {
19005                     return(stat);
19006                 }
19007             }
19008         }
19009     }
19010     if(block_type == TNG_PARTICLE_BLOCK_DATA)
19011     {
19012         if(p_data->last_retrieved_frame < 0)
19013         {
19014             i = p_data->first_frame_with_data;
19015         }
19016         else
19017         {
19018             i = p_data->last_retrieved_frame;
19019         }
19020     }
19021     else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
19022     {
19023         if(np_data->last_retrieved_frame < 0)
19024         {
19025             i = np_data->first_frame_with_data;
19026         }
19027         else
19028         {
19029             i = np_data->last_retrieved_frame;
19030         }
19031     }
19032     else
19033     {
19034         return(TNG_FAILURE);
19035     }
19036     if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
19037     {
19038         stat = tng_frame_set_of_frame_find(tng_data, i);
19039         if(stat != TNG_SUCCESS)
19040         {
19041             return(stat);
19042         }
19043         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
19044         if(stat != TNG_SUCCESS)
19045         {
19046             fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
19047                 __FILE__, __LINE__);
19048             return(stat);
19049         }
19050     }
19051     if(block_type == TNG_PARTICLE_BLOCK_DATA)
19052     {
19053         *codec_id = p_data->codec_id;
19054         *factor   = p_data->compression_multiplier;
19055     }
19056     else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
19057     {
19058         *codec_id = np_data->codec_id;
19059         *factor   = np_data->compression_multiplier;
19060     }
19061     return(TNG_SUCCESS);
19062 }
19063
19064 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_next_frame_present_data_blocks_find
19065                 (tng_trajectory_t tng_data,
19066                  int64_t current_frame,
19067                  const int64_t n_requested_data_block_ids,
19068                  const int64_t *requested_data_block_ids,
19069                  int64_t *next_frame,
19070                  int64_t *n_data_blocks_in_next_frame,
19071                  int64_t **data_block_ids_in_next_frame)
19072 {
19073     tng_trajectory_frame_set_t frame_set;
19074     tng_function_status stat;
19075     tng_particle_data_t p_data;
19076     tng_non_particle_data_t np_data;
19077     tng_gen_block_t block;
19078     int64_t i, j, block_id, *temp;
19079     int64_t data_frame, frame_diff, min_diff;
19080     int64_t size, frame_set_file_pos;
19081     int found, read_all = 0;
19082     long file_pos;
19083
19084     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
19085     TNG_ASSERT(next_frame, "TNG library: The pointer to the next frame must not be NULL.");
19086     TNG_ASSERT(n_data_blocks_in_next_frame, "TNG library: The pointer to n_data_blocks_in_next_frame must not be NULL.");
19087     TNG_ASSERT(data_block_ids_in_next_frame, "TNG library: The pointer to the list of data block IDs must not be NULL.");
19088
19089     if(n_requested_data_block_ids)
19090     {
19091         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.");
19092         size = sizeof(int64_t) * n_requested_data_block_ids;
19093         temp = realloc(*data_block_ids_in_next_frame, size);
19094         if(!temp)
19095         {
19096             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
19097                     sizeof(int64_t) * (*n_data_blocks_in_next_frame),
19098                     __FILE__, __LINE__);
19099             free(*data_block_ids_in_next_frame);
19100             *data_block_ids_in_next_frame = 0;
19101             return(TNG_CRITICAL);
19102         }
19103         *data_block_ids_in_next_frame = temp;
19104     }
19105
19106     frame_set = &tng_data->current_trajectory_frame_set;
19107
19108     current_frame += 1;
19109
19110     if(current_frame < frame_set->first_frame ||
19111        current_frame >= frame_set->first_frame + frame_set->n_frames)
19112     {
19113         frame_set_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
19114         stat = tng_frame_set_of_frame_find(tng_data, current_frame);
19115         if(stat != TNG_SUCCESS)
19116         {
19117             /* If the frame set search found the frame set after the starting
19118              * frame set there is a gap in the frame sets. So, even if the frame
19119              * was not found the next frame with data is still in the found
19120              * frame set. */
19121             if(stat == TNG_CRITICAL || frame_set->prev_frame_set_file_pos !=
19122                frame_set_file_pos)
19123             {
19124                 return(stat);
19125             }
19126             current_frame = frame_set->first_frame;
19127         }
19128     }
19129
19130     /* Check for data blocks only if they have not already been found. */
19131     if(frame_set->n_particle_data_blocks <= 0 && frame_set->n_data_blocks <= 0)
19132     {
19133         file_pos = ftell(tng_data->input_file);
19134         if(file_pos < tng_data->input_file_len)
19135         {
19136             tng_block_init(&block);
19137             stat = tng_block_header_read(tng_data, block);
19138             while(file_pos < tng_data->input_file_len &&
19139                 stat != TNG_CRITICAL &&
19140                 block->id != TNG_TRAJECTORY_FRAME_SET &&
19141                 block->id != -1)
19142             {
19143                 stat = tng_block_read_next(tng_data, block,
19144                                         TNG_USE_HASH);
19145                 if(stat != TNG_CRITICAL)
19146                 {
19147                     file_pos = ftell(tng_data->input_file);
19148                     if(file_pos < tng_data->input_file_len)
19149                     {
19150                         stat = tng_block_header_read(tng_data, block);
19151                     }
19152                 }
19153             }
19154             tng_block_destroy(&block);
19155             if(stat == TNG_CRITICAL)
19156             {
19157                 fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
19158                         file_pos, __FILE__, __LINE__);
19159                 return(stat);
19160             }
19161         }
19162         read_all = 1;
19163     }
19164
19165     min_diff = -1;
19166
19167     *n_data_blocks_in_next_frame = 0;
19168
19169     for(i = 0; i < frame_set->n_particle_data_blocks; i++)
19170     {
19171         p_data = &frame_set->tr_particle_data[i];
19172         block_id = p_data->block_id;
19173
19174         if(n_requested_data_block_ids > 0)
19175         {
19176             found = 0;
19177             for(j = 0; j < n_requested_data_block_ids; j++)
19178             {
19179                 if(block_id == requested_data_block_ids[j])
19180                 {
19181                     found = 1;
19182                     break;
19183                 }
19184             }
19185             if(!found)
19186             {
19187                 continue;
19188             }
19189         }
19190
19191         if(!read_all && (p_data->last_retrieved_frame < frame_set->first_frame ||
19192            p_data->last_retrieved_frame >=
19193            frame_set->first_frame + frame_set->n_frames))
19194         {
19195             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data,
19196                                                                       TNG_USE_HASH, block_id);
19197             if(stat == TNG_CRITICAL)
19198             {
19199                 fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
19200                     __FILE__, __LINE__);
19201                 return(stat);
19202             }
19203             if(stat == TNG_FAILURE)
19204             {
19205                 continue;
19206             }
19207         }
19208         if(frame_set->first_frame != current_frame &&
19209            p_data->last_retrieved_frame >= 0)
19210         {
19211             data_frame = p_data->last_retrieved_frame + p_data->stride_length;
19212         }
19213         else
19214         {
19215             data_frame = p_data->first_frame_with_data;
19216         }
19217         frame_diff = data_frame - current_frame;
19218         if(frame_diff < 0)
19219         {
19220             continue;
19221         }
19222         if(min_diff == -1 || frame_diff <= min_diff)
19223         {
19224             if(frame_diff < min_diff)
19225             {
19226                 *n_data_blocks_in_next_frame = 1;
19227             }
19228             else
19229             {
19230                 *n_data_blocks_in_next_frame += 1;
19231             }
19232             if(n_requested_data_block_ids <= 0)
19233             {
19234                 size = sizeof(int64_t) * (*n_data_blocks_in_next_frame);
19235                 temp = realloc(*data_block_ids_in_next_frame, size);
19236                 if(!temp)
19237                 {
19238                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
19239                            sizeof(int64_t) * (*n_data_blocks_in_next_frame),
19240                            __FILE__, __LINE__);
19241                     free(*data_block_ids_in_next_frame);
19242                     *data_block_ids_in_next_frame = 0;
19243                     return(TNG_CRITICAL);
19244                 }
19245                 *data_block_ids_in_next_frame = temp;
19246             }
19247             else
19248             {
19249                 TNG_ASSERT(*n_data_blocks_in_next_frame <= n_requested_data_block_ids, "TNG library: Array of data block IDs out of bounds");
19250             }
19251             (*data_block_ids_in_next_frame)[(*n_data_blocks_in_next_frame) - 1] = block_id;
19252
19253             min_diff = frame_diff;
19254         }
19255     }
19256     for(i = 0; i < frame_set->n_data_blocks; i++)
19257     {
19258         np_data = &frame_set->tr_data[i];
19259         block_id = np_data->block_id;
19260
19261         if(n_requested_data_block_ids > 0)
19262         {
19263             found = 0;
19264             for(j = 0; j < n_requested_data_block_ids; j++)
19265             {
19266                 if(block_id == requested_data_block_ids[j])
19267                 {
19268                     found = 1;
19269                     break;
19270                 }
19271             }
19272             if(!found)
19273             {
19274                 continue;
19275             }
19276         }
19277
19278         if(!read_all && (np_data->last_retrieved_frame < frame_set->first_frame ||
19279            np_data->last_retrieved_frame >=
19280            frame_set->first_frame + frame_set->n_frames))
19281         {
19282             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data,
19283                                                                       TNG_USE_HASH, block_id);
19284             if(stat == TNG_CRITICAL)
19285             {
19286                 fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
19287                     __FILE__, __LINE__);
19288                 return(stat);
19289             }
19290             if(stat == TNG_FAILURE)
19291             {
19292                 continue;
19293             }
19294         }
19295         if(frame_set->first_frame != current_frame &&
19296            np_data->last_retrieved_frame >= 0)
19297         {
19298             data_frame = np_data->last_retrieved_frame + np_data->stride_length;
19299         }
19300         else
19301         {
19302             data_frame = np_data->first_frame_with_data;
19303         }
19304         frame_diff = data_frame - current_frame;
19305         if(frame_diff < 0)
19306         {
19307             continue;
19308         }
19309         if(min_diff == -1 || frame_diff <= min_diff)
19310         {
19311             if(frame_diff < min_diff)
19312             {
19313                 *n_data_blocks_in_next_frame = 1;
19314             }
19315             else
19316             {
19317                 *n_data_blocks_in_next_frame += 1;
19318             }
19319             if(n_requested_data_block_ids <= 0)
19320             {
19321                 size = sizeof(int64_t) * (*n_data_blocks_in_next_frame);
19322                 temp = realloc(*data_block_ids_in_next_frame, size);
19323                 if(!temp)
19324                 {
19325                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
19326                            sizeof(int64_t) * (*n_data_blocks_in_next_frame),
19327                            __FILE__, __LINE__);
19328                     free(*data_block_ids_in_next_frame);
19329                     *data_block_ids_in_next_frame = 0;
19330                     return(TNG_CRITICAL);
19331                 }
19332                 *data_block_ids_in_next_frame = temp;
19333             }
19334             else
19335             {
19336                 TNG_ASSERT(*n_data_blocks_in_next_frame <= n_requested_data_block_ids, "TNG library: Array of data block IDs out of bounds");
19337             }
19338             (*data_block_ids_in_next_frame)[(*n_data_blocks_in_next_frame) - 1] = block_id;
19339
19340             min_diff = frame_diff;
19341         }
19342     }
19343     if(min_diff < 0)
19344     {
19345         return(TNG_FAILURE);
19346     }
19347     *next_frame = current_frame + min_diff;
19348
19349     return(TNG_SUCCESS);
19350 }
19351
19352 /*
19353 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_all_data_block_types_get
19354                 (tng_trajectory_t tng_data,
19355                  int64_t *n_data_blocks,
19356                  int64_t **data_block_ids,
19357                  char ***data_block_names,
19358                  int64_t **stride_lengths,
19359                  int64_t **n_values_per_frame,
19360                  char **block_types,
19361                  char **dependencies,
19362                  char **compressions)
19363 {
19364     tng_gen_block_t block;
19365     long orig_file_pos, file_pos;
19366
19367     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
19368     TNG_ASSERT(n_data_blocks, "TNG library: The pointer to n_data_blocks must not be NULL.");
19369     TNG_ASSERT(data_block_ids, "TNG library: The pointer to the list of data block IDs must not be NULL.");
19370     TNG_ASSERT(data_block_names, "TNG library: The pointer to the list of data block names must not be NULL.");
19371     TNG_ASSERT(stride_lengths, "TNG library: The pointer to the list of stride lengths must not be NULL.");
19372
19373     orig_file_pos = ftell(tng_data->input_file);
19374
19375     if(!tng_data->input_file_len)
19376     {
19377         fseek(tng_data->input_file, 0, SEEK_END);
19378         tng_data->input_file_len = ftell(tng_data->input_file);
19379     }
19380
19381     fseek(tng_data->input_file, 0, SEEK_SET);
19382     file_pos = 0;
19383
19384     *n_data_blocks = 0;
19385
19386     tng_block_init(&block);
19387
19388     while(file_pos < tng_data->input_file_len &&
19389           tng_block_header_read(tng_data, block) != TNG_CRITICAL)
19390     {
19391         if(block->id > TNG_TRAJECTORY_FRAME_SET)
19392         {
19393
19394         }
19395         file_pos += (long)(block->block_contents_size + block->header_contents_size);
19396         fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
19397     }
19398
19399     fseek(tng_data->input_file, orig_file_pos, SEEK_SET);
19400
19401     return(TNG_SUCCESS);
19402 }
19403 */
19404 tng_function_status DECLSPECDLLEXPORT tng_util_prepare_append_after_frame
19405                 (tng_trajectory_t tng_data,
19406                  const int64_t prev_frame)
19407 {
19408     tng_function_status stat;
19409     FILE *temp = tng_data->input_file;
19410
19411     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
19412     TNG_ASSERT(prev_frame >= 0, "TNG library: The previous frame must not be negative.");
19413
19414     tng_data->input_file = tng_data->output_file;
19415
19416     stat = tng_frame_set_of_frame_find(tng_data, prev_frame);
19417     if(stat != TNG_SUCCESS)
19418     {
19419         return(stat);
19420     }
19421
19422     tng_data->current_trajectory_frame_set_output_file_pos =
19423     tng_data->current_trajectory_frame_set_input_file_pos;
19424
19425     tng_data->input_file = temp;
19426
19427     return(TNG_SUCCESS);
19428 }