aboutsummaryrefslogtreecommitdiffstats
path: root/src/main.rs
diff options
context:
space:
mode:
authorHarald Eilertsen <haraldei@anduin.net>2020-11-25 23:01:29 +0100
committerHarald Eilertsen <haraldei@anduin.net>2020-11-26 14:49:09 +0100
commit76705a7ac6d404a9db709d45190767b3e8be24c9 (patch)
tree2c652db8e906c92c02a52ff13bda5df566dc8086 /src/main.rs
parent7d2fb776b77e10e64f5fdbf8d36676f13f1832d0 (diff)
downloadcbconv-76705a7ac6d404a9db709d45190767b3e8be24c9.tar.gz
cbconv-76705a7ac6d404a9db709d45190767b3e8be24c9.tar.bz2
cbconv-76705a7ac6d404a9db709d45190767b3e8be24c9.zip
A somewhat new start.
Split the file into chunks (with their payload) to begin with. This way it will be easier to parse each chunk separately. At least that's the idea. Let's see how it goes.
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs96
1 files changed, 57 insertions, 39 deletions
diff --git a/src/main.rs b/src/main.rs
index 9b9c12f..414f1c0 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -15,13 +15,18 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+mod cubase_project;
+
+use cubase_project::*;
+
use nom::{
branch::alt,
bytes::complete::*,
- multi::{count, length_data, many0},
+ multi::{count, length_data, length_value, many0},
number::complete::*,
sequence::tuple,
Finish,
+ InputTake,
IResult,
};
use std::{
@@ -313,21 +318,53 @@ fn chunk<'a>(data: &'a [u8]) -> IResult<&'a [u8], ()> {
Ok((rest, ()))
}
+struct RiffChunk<'a> {
+ fourcc: &'a str,
+ payload: &'a [u8],
+}
+
+fn riff_chunk<'a>(i: &'a [u8]) -> IResult<&'a [u8], RiffChunk> {
+ let (r, (fourcc, payload)) = tuple((fourcc, length_data(be_u32)))(i)?;
+ Ok((r, RiffChunk { fourcc, payload }))
+}
+
+
/**
- * Parse the Cubase project file header.
+ * Split file into individual chunks.
+ *
+ * A Cubase project file is a RIFF file.
+ *
+ * That is almost. There's a strange extra tag "NUND" between the root (RIFF) header and the
+ * rest of the chunks. This would have been ok, if the NUND tag was followed by a length field,
+ * as it would just be another chunk. This is not the case however, the tag is followed
+ * immefiately by another chunk header.
*
- * A Cubase project file is almost a standard RIFF file, with the exception of an
- * extra fourcc (NUND) following the global RIFF header. The extra (NUND) fourcc
- * is _not_ followed by the length of the chunk, but rather immediately followed by
- * the next chunk.
+ * To make it even worse, the chunk size of the root chunk is four bytes short, so this makes
+ * the file parser itself a bit more complex than what it needs to be.
*/
-fn file_hdr<'a>(data: &'a [u8]) -> IResult<&'a [u8], ()> {
- let (rest, (_, len, _)) = tuple((tag("RIFF"), be_u32, tag("NUND")))(data)?;
- println!("RIFF: {}, NUND", len);
- Ok((rest, ()))
+fn split_chunks<'a>(data: &'a [u8]) -> IResult<&'a [u8], Vec<RiffChunk<'a>>> {
+ let (r, (_, (_, chunks))) =
+ tuple((
+ tag(b"RIFF"),
+ length_value(
+ payload_len,
+ tuple((tag(b"NUND"), many0(riff_chunk)))
+ )
+ ))(&data)?;
+ Ok((r, chunks))
}
-pub struct CubaseProject;
+/**
+ * Get the correct payload length from the root chunk of the file.
+ *
+ * Cubase incorrectly specifies the chunk size four bytes less than what it really is, probably due
+ * to the strange inserted "NUND" tag that don't really belong anywhere. This parser fixes that by
+ * adding four to the size read from the file.
+ */
+fn payload_len<'a>(data: &'a [u8]) -> IResult<&'a [u8], u32> {
+ let (r, len) = be_u32(data)?;
+ Ok((r, len + 4))
+}
pub fn parse_cubase_project<P>(filename: P) -> Result<CubaseProject, Box<dyn Error>>
where
@@ -336,41 +373,22 @@ where
println!("Reading {}...", filename.as_ref().to_str().ok_or("Invalid file name")?);
let data = std::fs::read(filename)?;
- let (rest, _) = tuple((file_hdr, many0(chunk)))(&data)
+ let (rest, chunks) = split_chunks(&data)
.finish()
.map_err(|e| format!("{:?}", e))?;
println!("Rest: {}", rest.len());
- // let mut rest = chunk.payload;
-
- // while dbg!(rest.len()) > 0 {
- // let (r, chunk) = parse_chunk(&rest).unwrap();
- // println!(" Chunk id : {}", chunk.tag);
- // println!(" Chunk data size : {}/{} bytes", chunk.len, chunk.payload.len());
-
- // match chunk.tag {
- // "NUNDROOT" | "ROOT" => {
- // let (_r, hm) = parse_nundroot(&chunk.payload).unwrap();
- // println!(" data : {:?}", hm);
- // },
- // "ARCH" => {
- // let (_r, n) = node(&chunk.payload).unwrap();
- // println!(" {}: {{", n.nodeclass);
- // println!(" {:#?}", n.value);
- // println!(" }},");
- // },
- // _ => (),
- // };
-
- // rest = r;
- // std::thread::sleep(std::time::Duration::from_millis(200));
- // }
-
- Ok(CubaseProject {})
+ let proj = CubaseProject::default();
+
+ for chunk in chunks {
+ println!("{}: {}", chunk.fourcc, chunk.payload.len());
+ }
+
+ Ok(proj)
}
-fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
+fn main() -> Result<(), Box<dyn Error>> {
let filename = std::env::args()
.skip(1)
.next()